Skip to content

Commit

Permalink
pre-inferring data sanitazation (#5050)
Browse files Browse the repository at this point in the history
* extractFieldExamples: omit not defined fields

this is especially helpful with ___NODE fields - plugins/users don't have to test if there are any values and be confident that empty ___NODE values or arrays will just be omitted and not error out during bootstrap

* sanitize field owner key when using createNodeField with name containing ___NODE

this fixes issue with inferring fieldOwners types - gatsby would try to link to not existing nodes
  • Loading branch information
pieh authored and KyleAMathews committed Apr 24, 2018
1 parent e78a27e commit e1bebad
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 37 deletions.
11 changes: 9 additions & 2 deletions packages/gatsby/src/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,15 @@ actions.createNodeField = (
node.fields = {}
}

/**
* Normalized name of the field that will be used in schema
*/
const schemaFieldName = _.includes(name, `___NODE`)
? name.split(`___`)[0]
: name

// Check that this field isn't owned by another plugin.
const fieldOwner = node.internal.fieldOwners[name]
const fieldOwner = node.internal.fieldOwners[schemaFieldName]
if (fieldOwner && fieldOwner !== plugin.name) {
throw new Error(
stripIndent`
Expand All @@ -765,7 +772,7 @@ actions.createNodeField = (

// Update node
node.fields[name] = value
node.internal.fieldOwners[name] = plugin.name
node.internal.fieldOwners[schemaFieldName] = plugin.name

return {
type: `ADD_FIELD_TO_NODE`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ Object {
},
},
"date": "2006-07-22T22:39:53.000Z",
"emptyArray": null,
"frontmatter": Object {
"blue": 100,
"circle": "happy",
Expand All @@ -64,7 +63,6 @@ Object {
"title": "The world of dash and adventure",
},
"hair": 1,
"iAmNull": null,
"key-with..unsupported-values": true,
"name": "The Mad Max",
"nestedArrays": Array [
Expand Down
12 changes: 6 additions & 6 deletions packages/gatsby/src/schema/__tests__/data-tree-utils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ describe(`Gatsby data tree utils`, () => {
expect(getExampleValues(nodes)).toMatchSnapshot()
})

it(`null fields should have a null value`, () => {
expect(getExampleValues(nodes).iAmNull).toBeNull()
it(`skips null fields`, () => {
expect(getExampleValues(nodes).iAmNull).not.toBeDefined()
})

it(`should not mutate the nodes`, () => {
Expand All @@ -111,8 +111,8 @@ describe(`Gatsby data tree utils`, () => {
expect(nodes[3].context.nestedObject.someOtherProperty).toEqual(3)
})

it(`turns empty or sparse arrays to null`, () => {
expect(getExampleValues(nodes).emptyArray).toBeNull()
it(`skips empty or sparse arrays`, () => {
expect(getExampleValues(nodes).emptyArray).not.toBeDefined()
expect(getExampleValues(nodes).hair).toBeDefined()
})

Expand Down Expand Up @@ -156,11 +156,11 @@ describe(`Gatsby data tree utils`, () => {
it(`skips unsupported types`, () => {
// Skips functions
let example = getExampleValues([{ foo: () => {} }])
expect(example.foo).toEqual(null)
expect(example.foo).not.toBeDefined()

// Skips array of functions
example = getExampleValues([{ foo: [() => {}] }])
expect(example.foo).toEqual(null)
expect(example.foo).not.toBeDefined()
})
})

Expand Down
57 changes: 30 additions & 27 deletions packages/gatsby/src/schema/data-tree-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,34 +153,37 @@ const extractFieldExamples = (nodes: object[], selector: string) => {
// get list of keys in all nodes
const allKeys = _.uniq(_.flatten(nodes.map(_.keys)))

return _.zipObject(
allKeys,
allKeys.map(key => {
const nextSelector = selector && `${selector}.${key}`

const nodeWithValues = nodes.filter(node => {
if (!node) return false

const value = node[key]
if (_.isObject(value)) {
return !isEmptyObjectOrArray(value)
} else {
return isDefined(value)
}
return _.pickBy(
_.zipObject(
allKeys,
allKeys.map(key => {
const nextSelector = selector && `${selector}.${key}`

const nodeWithValues = nodes.filter(node => {
if (!node) return false

const value = node[key]
if (_.isObject(value)) {
return !isEmptyObjectOrArray(value)
} else {
return isDefined(value)
}
})

// we want to keep track of nodes as we need it to get origin of data
const entries = nodeWithValues.map(node => {
const value = node[key]
return {
value,
parent: node,
...extractTypes(value),
}
})

return extractFromEntries(entries, nextSelector, key)
})

// we want to keep track of nodes as we need it to get origin of data
const entries = nodeWithValues.map(node => {
const value = node[key]
return {
value,
parent: node,
...extractTypes(value),
}
})

return extractFromEntries(entries, nextSelector, key)
})
),
isDefined
)
}

Expand Down

0 comments on commit e1bebad

Please sign in to comment.