Skip to content

Commit

Permalink
fix(gatsby-source-wordpress): schema customization errors (#30358)
Browse files Browse the repository at this point in the history
* use new reporter.panic signature with error code for schema customization

* add the prefixed typename as a node property when creating nodes to prevent gql errors with interfaces

* fix union types that have a field called "type"

* prevent excluded types from throwing errors in connection fields

* test node interface resolution

* test that interfaces that are mixed node and non-node resolve

* prefix the __typename field in the default resolver for Gatsby v3

* an interface type is only a gatsby node type if all implementing types are gatsby node types

* exclude Commenter.databaseId in int tests to get around WPGQL bug

* only return null if there's no gatsby node AND no resolved field data
  • Loading branch information
TylerBarnes authored Mar 24, 2021
1 parent 096eb38 commit 5c9b744
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,62 @@ Array [
],
"name": "WpComment",
},
Object {
"fields": Array [
"databaseId",
"email",
"id",
"name",
"url",
"nodeType",
"parent",
"children",
"internal",
],
"name": "WpCommentAuthor",
},
Object {
"fields": Array [
"totalCount",
"edges",
"nodes",
"pageInfo",
"distinct",
"group",
],
"name": "WpCommentAuthorConnection",
},
Object {
"fields": Array [
"next",
"node",
"previous",
],
"name": "WpCommentAuthorEdge",
},
Object {
"fields": null,
"name": "WpCommentAuthorFieldsEnum",
},
Object {
"fields": null,
"name": "WpCommentAuthorFilterInput",
},
Object {
"fields": Array [
"totalCount",
"edges",
"nodes",
"pageInfo",
"field",
"fieldValue",
],
"name": "WpCommentAuthorGroupConnection",
},
Object {
"fields": null,
"name": "WpCommentAuthorSortInput",
},
Object {
"fields": Array [
"totalCount",
Expand Down
3 changes: 3 additions & 0 deletions integration-tests/gatsby-source-wordpress/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const wpPluginOptions = !process.env.DEFAULT_PLUGIN_OPTIONS
`registeredDate`,
],
},
Commenter: {
excludeFieldNames: [`databaseId`],
},
Post: {
limit:
process.env.NODE_ENV === `development`
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/gatsby-source-wordpress/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react"

export default function index() {
return <div>Index page</div>
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ describe(`data resolution`, () => {
expect(data[`allWpPage`].totalCount).toBe(1)
expect(data[`allWpPost`].totalCount).toBe(1)
expect(data[`allWpComment`].totalCount).toBe(1)
// expect(data[`allWpProject`].totalCount).toBe(1)
expect(data[`allWpTaxonomy`].totalCount).toBe(3)
expect(data[`allWpCategory`].totalCount).toBe(9)
expect(data[`allWpMenu`].totalCount).toBe(1)
expect(data[`allWpMenuItem`].totalCount).toBe(4)
// expect(data[`allWpTeamMember`].totalCount).toBe(1)
expect(data[`allWpPostFormat`].totalCount).toBe(0)
expect(data[`allWpContentType`].totalCount).toBe(6)
})
Expand All @@ -53,6 +51,61 @@ describe(`data resolution`, () => {
},
})

it(`resolves node interfaces without errors`, async () => {
const query = /* GraphQL */ `
query {
allWpTermNode {
nodes {
id
}
}
allWpContentNode {
nodes {
id
}
}
}
`

// this will throw if there are gql errors
const gatsbyResult = await fetchGraphql({
url,
query,
})

expect(gatsbyResult.data.allWpTermNode.nodes.length).toBe(14)
expect(gatsbyResult.data.allWpContentNode.nodes.length).toBe(12)
})

it(`resolves interface fields which are a mix of Gatsby nodes and regular object data with no node`, async () => {
const query = /* GraphQL */ `
query {
wpPost(id: { eq: "cG9zdDox" }) {
id
comments {
nodes {
author {
# this is an interface of WpUser (Gatsby node type) and WpCommentAuthor (no node for this so needs to be fetched on the comment)
node {
name
}
}
}
}
}
}
`

// this will throw an error if there are gql errors
const gatsbyResult = await fetchGraphql({
url,
query,
})

expect(gatsbyResult.data.wpPost.comments.nodes.length).toBe(1)
})

it(`resolves hierarchichal categories`, async () => {
const gatsbyResult = await fetchGraphql({
url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ const unionType = typeBuilderApi => {
name: buildTypeName(type.name),
types,
resolveType: node => {
if (node.type) {
return buildTypeName(node.type)
}

if (node.__typename) {
return buildTypeName(node.__typename)
}
Expand Down Expand Up @@ -104,7 +100,7 @@ const interfaceType = typeBuilderApi => {
} else {
// otherwise this is a regular interface type so we need to resolve the type name
typeDef.resolveType = node =>
node && node.__typename ? buildTypeName(node.__typename) : null
node?.__typename ? buildTypeName(node.__typename) : null
}

// @todo add this as a plugin option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export const buildTypeName = name => {
name = `FilterType`
}

if (name.startsWith(prefix)) {
return name
}

return prefix + name
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { fieldOfTypeWasFetched } from "./helpers"
import buildType from "./build-types"
import { getGatsbyNodeTypeNames } from "../source-nodes/fetch-nodes/fetch-nodes"
import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded"
import { formatLogMessage } from "../../utils/format-log-message"
import { CODES } from "../../utils/report"

/**
* createSchemaCustomization
Expand Down Expand Up @@ -96,7 +98,13 @@ const createSchemaCustomization = async api => {
try {
await customizeSchema(api)
} catch (e) {
api.reporter.panic(e)
api.reporter.panic({
id: CODES.SourcePluginCodeError,
error: e,
context: {
sourceMessage: formatLogMessage(e.message),
},
})
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { findTypeName } from "~/steps/create-schema-customization/helpers"

import { buildGatsbyNodeObjectResolver } from "~/steps/create-schema-customization/transform-fields/transform-object"
import { buildTypeName } from "../helpers"

export const buildDefaultResolver = transformerApi => (source, _, context) => {
const { fieldName, field, gatsbyNodeTypes } = transformerApi
Expand Down Expand Up @@ -45,6 +46,12 @@ export const buildDefaultResolver = transformerApi => (source, _, context) => {
finalFieldValue = aliasedField2
}

if (finalFieldValue?.__typename) {
// in Gatsby V3 this property is used to determine the type of an interface field
// instead of the resolveType fn. This means we need to prefix it so that gql doesn't throw errors about missing types.
finalFieldValue.__typename = buildTypeName(finalFieldValue.__typename)
}

const isANodeConnection =
// if this field has just an id and typename
finalFieldValue?.id &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ export const buildGatsbyNodeObjectResolver = ({ field, fieldName }) => async (

const queryInfo = getQueryInfoByTypeName(field.type.name)

if (!queryInfo) {
// if we don't have query info for a type
// it probably means this type is excluded in plugin options
return null
}

const isLazyMediaItem =
queryInfo.typeInfo.nodesTypeName === `MediaItem` &&
queryInfo.settings.lazyNodes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ export const transformUnion = ({ field, fieldName }) => {

if (gatsbyNode) {
return gatsbyNode
} else {
return null
}
}

return resolvedField
return resolvedField ?? null
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,10 @@ export function transformField({
const isAGatsbyNode =
// if this is a gatsby node type
gatsbyNodesInfo.typeNames.includes(typeName) ||
// or this type has a possible type which is a gatsby node type
// or all possible types on this type are Gatsby node types
typeMap
.get(typeName)
?.possibleTypes?.find(possibleType =>
?.possibleTypes?.every(possibleType =>
gatsbyNodesInfo.typeNames.includes(possibleType.name)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ export const createNodeWithSideEffects = ({
})
}

const builtTypename = buildTypeName(node.__typename)

let remoteNode = {
...node,
__typename: builtTypename,
id: node.id,
parent: null,
internal: {
contentDigest: createContentDigest(node),
type: type || buildTypeName(node.type),
type: type || builtTypename,
},
}

Expand Down

0 comments on commit 5c9b744

Please sign in to comment.