diff --git a/packages/gatsby/src/schema/__tests__/infer-graphql-input-type-test.js b/packages/gatsby/src/schema/__tests__/infer-graphql-input-type-test.js index 5adb69b76bfa5..e829f9e043dab 100644 --- a/packages/gatsby/src/schema/__tests__/infer-graphql-input-type-test.js +++ b/packages/gatsby/src/schema/__tests__/infer-graphql-input-type-test.js @@ -130,6 +130,22 @@ describe(`GraphQL Input args`, () => { circle: `happy`, }, boolean: false, + data: { + tags: [ + { + tag: { + document: [ + { + data: { + tag: `Design System`, + }, + number: 3, + }, + ], + }, + }, + ], + }, }, { index: 2, @@ -149,6 +165,33 @@ describe(`GraphQL Input args`, () => { blue: 10010, circle: `happy`, }, + data: { + tags: [ + { + tag: { + document: [ + { + data: { + tag: `Gatsby`, + }, + }, + ], + }, + }, + { + tag: { + document: [ + { + data: { + tag: `Design System`, + }, + number: 5, + }, + ], + }, + }, + ], + }, }, ] @@ -505,18 +548,45 @@ describe(`GraphQL Input args`, () => { expect(result.data.allNode.edges[0].node.name).toEqual(`The Mad Wax`) }) - it(`handles the glob operator`, async () => { + it(`handles the in operator for array of objects`, async () => { let result = await queryResult( nodes, ` { - allNode(limit: 10, filter: {name: { glob: "*Wax" }}) { - edges { node { name }} + test1:allNode(filter: {data: {tags: {elemMatch: {tag: {document: {elemMatch: {data: {tag: {eq: "Gatsby"}}}}}}}}}) { + edges { node { index }} + } + test2:allNode(filter: {data: {tags: {elemMatch: {tag: {document: {elemMatch: {data: {tag: {eq: "Design System"}}}}}}}}}) { + edges { node { index }} + } + test3:allNode(filter: {data: {tags: {elemMatch: {tag: {document: {elemMatch: {number: {lt: 4}}}}}}}}) { + edges { node { index }} } } ` ) expect(result.errors).not.toBeDefined() + expect(result.data.test1.edges.length).toEqual(1) + expect(result.data.test1.edges[0].node.index).toEqual(2) + expect(result.data.test2.edges.length).toEqual(2) + expect(result.data.test2.edges[0].node.index).toEqual(1) + expect(result.data.test2.edges[1].node.index).toEqual(2) + expect(result.data.test3.edges.length).toEqual(1) + expect(result.data.test3.edges[0].node.index).toEqual(1) + }) + + it(`handles the glob operator`, async () => { + let result = await queryResult( + nodes, + ` + { + allNode(limit: 10, filter: {name: { glob: "*Wax" }}) { + edges { node { name }} + } + } + ` + ) + expect(result.errors).not.toBeDefined() expect(result.data.allNode.edges.length).toEqual(2) expect(result.data.allNode.edges[0].node.name).toEqual(`The Mad Wax`) }) diff --git a/packages/gatsby/src/schema/infer-graphql-input-fields-from-fields.js b/packages/gatsby/src/schema/infer-graphql-input-fields-from-fields.js index b6f05874fb906..d22d987f34928 100644 --- a/packages/gatsby/src/schema/infer-graphql-input-fields-from-fields.js +++ b/packages/gatsby/src/schema/infer-graphql-input-fields-from-fields.js @@ -148,12 +148,21 @@ function convertToInputFilter( const innerFilter = convertToInputFilter(`${prefix}ListElem`, innerType) const innerFields = innerFilter ? innerFilter.getFields() : {} - return new GraphQLInputObjectType({ - name: createTypeName(`${prefix}QueryList`), - fields: { + let fields + if (innerType instanceof GraphQLInputObjectType) { + fields = { + elemMatch: { type: innerFilter }, + } + } else { + fields = { ...innerFields, in: { type: new GraphQLList(innerType) }, - }, + } + } + + return new GraphQLInputObjectType({ + name: createTypeName(`${prefix}QueryList`), + fields, }) } else if (type instanceof GraphQLNonNull) { return convertToInputFilter(prefix, type.ofType) diff --git a/packages/gatsby/src/schema/infer-graphql-input-fields.js b/packages/gatsby/src/schema/infer-graphql-input-fields.js index c67f3dfa9c7c0..c8cdbc2e8c5b5 100644 --- a/packages/gatsby/src/schema/infer-graphql-input-fields.js +++ b/packages/gatsby/src/schema/infer-graphql-input-fields.js @@ -125,13 +125,24 @@ function inferGraphQLInputFields({ ) } + let fields + if (headType === `object`) { + fields = { + elemMatch: { + type: inType, + }, + } + } else { + fields = { + ...typeFields(headType), + in: { type: new GraphQLList(inType) }, + } + } + return { type: new GraphQLInputObjectType({ name: createTypeName(`${prefix}QueryList`), - fields: { - ...typeFields(headType), - in: { type: new GraphQLList(inType) }, - }, + fields, }), } } diff --git a/packages/gatsby/src/schema/run-sift.js b/packages/gatsby/src/schema/run-sift.js index be8fa5fb47e2f..5139b2977c8de 100644 --- a/packages/gatsby/src/schema/run-sift.js +++ b/packages/gatsby/src/schema/run-sift.js @@ -43,7 +43,10 @@ module.exports = ({ const siftifyArgs = object => { const newObject = {} _.each(object, (v, k) => { - if (_.isObject(v) && !_.isArray(v)) { + if (_.isPlainObject(v)) { + if (k === `elemMatch`) { + k = `$elemMatch` + } newObject[k] = siftifyArgs(v) } else { // Compile regex first. @@ -64,7 +67,7 @@ module.exports = ({ // Build an object that excludes the innermost leafs, // this avoids including { eq: x } when resolving fields. function extractFieldsToSift(prekey, key, preobj, obj, val) { - if (_.isObject(val) && !_.isArray(val)) { + if (_.isPlainObject(val)) { _.forEach((val: any), (v, k) => { preobj[prekey] = obj extractFieldsToSift(key, k, obj, {}, v)