Skip to content

Commit 5c9b744

Browse files
authored
fix(gatsby-source-wordpress): schema customization errors (#30358)
* 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
1 parent 096eb38 commit 5c9b744

File tree

12 files changed

+153
-14
lines changed

12 files changed

+153
-14
lines changed

integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap

+56
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,62 @@ Array [
551551
],
552552
"name": "WpComment",
553553
},
554+
Object {
555+
"fields": Array [
556+
"databaseId",
557+
"email",
558+
"id",
559+
"name",
560+
"url",
561+
"nodeType",
562+
"parent",
563+
"children",
564+
"internal",
565+
],
566+
"name": "WpCommentAuthor",
567+
},
568+
Object {
569+
"fields": Array [
570+
"totalCount",
571+
"edges",
572+
"nodes",
573+
"pageInfo",
574+
"distinct",
575+
"group",
576+
],
577+
"name": "WpCommentAuthorConnection",
578+
},
579+
Object {
580+
"fields": Array [
581+
"next",
582+
"node",
583+
"previous",
584+
],
585+
"name": "WpCommentAuthorEdge",
586+
},
587+
Object {
588+
"fields": null,
589+
"name": "WpCommentAuthorFieldsEnum",
590+
},
591+
Object {
592+
"fields": null,
593+
"name": "WpCommentAuthorFilterInput",
594+
},
595+
Object {
596+
"fields": Array [
597+
"totalCount",
598+
"edges",
599+
"nodes",
600+
"pageInfo",
601+
"field",
602+
"fieldValue",
603+
],
604+
"name": "WpCommentAuthorGroupConnection",
605+
},
606+
Object {
607+
"fields": null,
608+
"name": "WpCommentAuthorSortInput",
609+
},
554610
Object {
555611
"fields": Array [
556612
"totalCount",

integration-tests/gatsby-source-wordpress/gatsby-config.js

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const wpPluginOptions = !process.env.DEFAULT_PLUGIN_OPTIONS
4848
`registeredDate`,
4949
],
5050
},
51+
Commenter: {
52+
excludeFieldNames: [`databaseId`],
53+
},
5154
Post: {
5255
limit:
5356
process.env.NODE_ENV === `development`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import React from "react"
2+
3+
export default function index() {
4+
return <div>Index page</div>
5+
}

integration-tests/gatsby-source-wordpress/test-fns/data-resolution.js

+55-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,10 @@ describe(`data resolution`, () => {
2929
expect(data[`allWpPage`].totalCount).toBe(1)
3030
expect(data[`allWpPost`].totalCount).toBe(1)
3131
expect(data[`allWpComment`].totalCount).toBe(1)
32-
// expect(data[`allWpProject`].totalCount).toBe(1)
3332
expect(data[`allWpTaxonomy`].totalCount).toBe(3)
3433
expect(data[`allWpCategory`].totalCount).toBe(9)
3534
expect(data[`allWpMenu`].totalCount).toBe(1)
3635
expect(data[`allWpMenuItem`].totalCount).toBe(4)
37-
// expect(data[`allWpTeamMember`].totalCount).toBe(1)
3836
expect(data[`allWpPostFormat`].totalCount).toBe(0)
3937
expect(data[`allWpContentType`].totalCount).toBe(6)
4038
})
@@ -53,6 +51,61 @@ describe(`data resolution`, () => {
5351
},
5452
})
5553

54+
it(`resolves node interfaces without errors`, async () => {
55+
const query = /* GraphQL */ `
56+
query {
57+
allWpTermNode {
58+
nodes {
59+
id
60+
}
61+
}
62+
63+
allWpContentNode {
64+
nodes {
65+
id
66+
}
67+
}
68+
}
69+
`
70+
71+
// this will throw if there are gql errors
72+
const gatsbyResult = await fetchGraphql({
73+
url,
74+
query,
75+
})
76+
77+
expect(gatsbyResult.data.allWpTermNode.nodes.length).toBe(14)
78+
expect(gatsbyResult.data.allWpContentNode.nodes.length).toBe(12)
79+
})
80+
81+
it(`resolves interface fields which are a mix of Gatsby nodes and regular object data with no node`, async () => {
82+
const query = /* GraphQL */ `
83+
query {
84+
wpPost(id: { eq: "cG9zdDox" }) {
85+
id
86+
comments {
87+
nodes {
88+
author {
89+
# this is an interface of WpUser (Gatsby node type) and WpCommentAuthor (no node for this so needs to be fetched on the comment)
90+
node {
91+
name
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
`
99+
100+
// this will throw an error if there are gql errors
101+
const gatsbyResult = await fetchGraphql({
102+
url,
103+
query,
104+
})
105+
106+
expect(gatsbyResult.data.wpPost.comments.nodes.length).toBe(1)
107+
})
108+
56109
it(`resolves hierarchichal categories`, async () => {
57110
const gatsbyResult = await fetchGraphql({
58111
url,

packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ const unionType = typeBuilderApi => {
2929
name: buildTypeName(type.name),
3030
types,
3131
resolveType: node => {
32-
if (node.type) {
33-
return buildTypeName(node.type)
34-
}
35-
3632
if (node.__typename) {
3733
return buildTypeName(node.__typename)
3834
}
@@ -104,7 +100,7 @@ const interfaceType = typeBuilderApi => {
104100
} else {
105101
// otherwise this is a regular interface type so we need to resolve the type name
106102
typeDef.resolveType = node =>
107-
node && node.__typename ? buildTypeName(node.__typename) : null
103+
node?.__typename ? buildTypeName(node.__typename) : null
108104
}
109105

110106
// @todo add this as a plugin option

packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export const buildTypeName = name => {
2424
name = `FilterType`
2525
}
2626

27+
if (name.startsWith(prefix)) {
28+
return name
29+
}
30+
2731
return prefix + name
2832
}
2933

packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { fieldOfTypeWasFetched } from "./helpers"
55
import buildType from "./build-types"
66
import { getGatsbyNodeTypeNames } from "../source-nodes/fetch-nodes/fetch-nodes"
77
import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded"
8+
import { formatLogMessage } from "../../utils/format-log-message"
9+
import { CODES } from "../../utils/report"
810

911
/**
1012
* createSchemaCustomization
@@ -96,7 +98,13 @@ const createSchemaCustomization = async api => {
9698
try {
9799
await customizeSchema(api)
98100
} catch (e) {
99-
api.reporter.panic(e)
101+
api.reporter.panic({
102+
id: CODES.SourcePluginCodeError,
103+
error: e,
104+
context: {
105+
sourceMessage: formatLogMessage(e.message),
106+
},
107+
})
100108
}
101109
}
102110

packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/default-resolver.js

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { findTypeName } from "~/steps/create-schema-customization/helpers"
22

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

56
export const buildDefaultResolver = transformerApi => (source, _, context) => {
67
const { fieldName, field, gatsbyNodeTypes } = transformerApi
@@ -45,6 +46,12 @@ export const buildDefaultResolver = transformerApi => (source, _, context) => {
4546
finalFieldValue = aliasedField2
4647
}
4748

49+
if (finalFieldValue?.__typename) {
50+
// in Gatsby V3 this property is used to determine the type of an interface field
51+
// instead of the resolveType fn. This means we need to prefix it so that gql doesn't throw errors about missing types.
52+
finalFieldValue.__typename = buildTypeName(finalFieldValue.__typename)
53+
}
54+
4855
const isANodeConnection =
4956
// if this field has just an id and typename
5057
finalFieldValue?.id &&

packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-object.js

+6
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ export const buildGatsbyNodeObjectResolver = ({ field, fieldName }) => async (
6464

6565
const queryInfo = getQueryInfoByTypeName(field.type.name)
6666

67+
if (!queryInfo) {
68+
// if we don't have query info for a type
69+
// it probably means this type is excluded in plugin options
70+
return null
71+
}
72+
6773
const isLazyMediaItem =
6874
queryInfo.typeInfo.nodesTypeName === `MediaItem` &&
6975
queryInfo.settings.lazyNodes

packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-union.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ export const transformUnion = ({ field, fieldName }) => {
1616

1717
if (gatsbyNode) {
1818
return gatsbyNode
19-
} else {
20-
return null
2119
}
2220
}
2321

24-
return resolvedField
22+
return resolvedField ?? null
2523
},
2624
}
2725
}

packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,10 @@ export function transformField({
303303
const isAGatsbyNode =
304304
// if this is a gatsby node type
305305
gatsbyNodesInfo.typeNames.includes(typeName) ||
306-
// or this type has a possible type which is a gatsby node type
306+
// or all possible types on this type are Gatsby node types
307307
typeMap
308308
.get(typeName)
309-
?.possibleTypes?.find(possibleType =>
309+
?.possibleTypes?.every(possibleType =>
310310
gatsbyNodesInfo.typeNames.includes(possibleType.name)
311311
)
312312

packages/gatsby-source-wordpress/src/steps/source-nodes/create-nodes/create-nodes.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,16 @@ export const createNodeWithSideEffects = ({
4848
})
4949
}
5050

51+
const builtTypename = buildTypeName(node.__typename)
52+
5153
let remoteNode = {
5254
...node,
55+
__typename: builtTypename,
5356
id: node.id,
5457
parent: null,
5558
internal: {
5659
contentDigest: createContentDigest(node),
57-
type: type || buildTypeName(node.type),
60+
type: type || builtTypename,
5861
},
5962
}
6063

0 commit comments

Comments
 (0)