Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(gatsby): print childOf directive for implicit child fields #28483

Merged
merged 7 commits into from
Dec 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ input Baz {
qux: Boolean
}

type FooChild implements Node @childOf(types: [\\"Test\\"]) @dontInfer {
bar: String
}

type Test implements Node @dontInfer {
foo: Int
}"
Expand Down Expand Up @@ -266,6 +270,10 @@ type OneMoreTest implements Node @dontInfer {

union ThisOrThat = AnotherTest | OneMoreTest

type FooChild implements Node @childOf(types: [\\"Test\\"]) @dontInfer {
bar: String
}

type Test implements Node @dontInfer {
foo: Int
}"
Expand Down Expand Up @@ -423,6 +431,10 @@ input Baz {
qux: Boolean
}

type FooChild implements Node @childOf(types: [\\"Test\\"]) @dontInfer {
bar: String
}

type Test implements Node @dontInfer {
foo: Int
}"
Expand Down
17 changes: 15 additions & 2 deletions packages/gatsby/src/schema/__tests__/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const { build } = require(`..`)
import { buildObjectType } from "../types/type-builders"
const { store } = require(`../../redux`)
const { actions } = require(`../../redux/actions/restricted`)
const { actions: publicActions } = require(`../../redux/actions/public`)
const { createParentChildLink } = publicActions
const { printTypeDefinitions } = actions

jest.mock(`fs-extra`)
Expand Down Expand Up @@ -41,14 +43,25 @@ jest.spyOn(global.Date.prototype, `toISOString`).mockReturnValue(`2019-01-01`)
describe(`Print type definitions`, () => {
beforeEach(() => {
store.dispatch({ type: `DELETE_CACHE` })
const node = {
const node1 = {
id: `test1`,
internal: {
type: `Test`,
},
children: [],
foo: 26,
}
store.dispatch({ type: `CREATE_NODE`, payload: { ...node } })
const node2 = {
id: `test2`,
parent: `test1`,
internal: {
type: `FooChild`,
},
bar: `bar`,
}
store.dispatch({ type: `CREATE_NODE`, payload: { ...node1 } })
store.dispatch({ type: `CREATE_NODE`, payload: { ...node2 } })
createParentChildLink({ parent: node1, child: node2 })
const typeDefs = []
typeDefs.push(`
type AnotherTest implements Node & ITest {
Expand Down
55 changes: 35 additions & 20 deletions packages/gatsby/src/schema/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ const updateSchemaComposer = async ({
inferenceMetadata,
parentSpan: activity.span,
})
addInferredChildOfExtensions({
schemaComposer,
})
activity.end()

activity = report.phantomActivity(`Processing types`, {
Expand Down Expand Up @@ -202,11 +205,6 @@ const processTypeComposer = async ({

if (typeComposer.hasInterface(`Node`)) {
await addNodeInterfaceFields({ schemaComposer, typeComposer, parentSpan })
await addImplicitConvenienceChildrenFields({
schemaComposer,
typeComposer,
parentSpan,
})
}
await determineSearchableFields({
schemaComposer,
Expand Down Expand Up @@ -999,15 +997,26 @@ const addConvenienceChildrenFields = ({ schemaComposer }) => {
})
}

const addImplicitConvenienceChildrenFields = ({
schemaComposer,
typeComposer,
}) => {
const addInferredChildOfExtensions = ({ schemaComposer }) => {
schemaComposer.forEach(typeComposer => {
if (
typeComposer instanceof ObjectTypeComposer &&
typeComposer.hasInterface(`Node`)
) {
addInferredChildOfExtension({
schemaComposer,
typeComposer,
})
}
})
}

const addInferredChildOfExtension = ({ schemaComposer, typeComposer }) => {
const shouldInfer = typeComposer.getExtension(`infer`)
// In Gatsby v3, when `@dontInfer` is set, children fields will not be
// created for parent-child relations set by plugins with
// In Gatsby v3, when `@dontInfer` is set, `@childOf` extension will not be
// automatically created for parent-child relations set by plugins with
// `createParentChildLink`. With `@dontInfer`, only parent-child
// relations explicitly set with the `childOf` extension will be added.
// relations explicitly set with the `@childOf` extension will be added.
// if (shouldInfer === false) return

const parentTypeName = typeComposer.getTypeName()
Expand All @@ -1016,12 +1025,12 @@ const addImplicitConvenienceChildrenFields = ({
const childNodesByType = groupChildNodesByType({ nodes })

Object.keys(childNodesByType).forEach(typeName => {
// Adding children fields to types with the `@dontInfer` extension is deprecated
if (shouldInfer === false) {
const childTypeComposer = schemaComposer.getAnyTC(typeName)
const childOfExtension = childTypeComposer.getExtension(`childOf`)
const childTypeComposer = schemaComposer.getAnyTC(typeName)
let childOfExtension = childTypeComposer.getExtension(`childOf`)

// Only warn when the parent-child relation has not been explicitly set with
if (shouldInfer === false) {
// Adding children fields to types with the `@dontInfer` extension is deprecated
// Only warn when the parent-child relation has not been explicitly set with `childOf` directive
if (
!childOfExtension ||
!childOfExtension.types.includes(parentTypeName)
Expand All @@ -1046,9 +1055,15 @@ const addImplicitConvenienceChildrenFields = ({
)
}
}

typeComposer.addFields(createChildrenField(typeName))
typeComposer.addFields(createChildField(typeName))
// Set `@childOf` extension automatically
// This will cause convenience children fields like `childImageSharp`
// to be added in `addConvenienceChildrenFields` method.
// Also required for proper printing of the `@childOf` directive in the snapshot plugin
if (!childOfExtension?.types) {
childOfExtension = { types: [] }
}
pieh marked this conversation as resolved.
Show resolved Hide resolved
childOfExtension.types.push(parentTypeName)
childTypeComposer.setExtension(`childOf`, childOfExtension)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The essence of this PR: instead of adding fields directly we add the childOf directive here. And fields are always added in a single place now - where this directive is processed (in addConvenienceChildrenFields):

children.forEach(child => {
typeComposer.addFields(createChildrenField(child.getTypeName()))
typeComposer.addFields(createChildField(child.getTypeName()))
})

})
}

Expand Down