graphql-compose-mongoose
graphql-compose-mongoose copied to clipboard
Fields on _operators are lost on child resolvers when using discriminators
When using discriminators the prepareChildResolver process (copyResolverArgTypes) will treat _operators, AND and OR as fields and call extendField from the baseResolver args to the childResolver args. This will overwrite the contents of these fields removing any specialisation found in the child resolver.
A child based query will result in a GraphQLError
clickedLinkEventFindMany( filter: { AND: [ { _operators: { url: { in: [ "url1", "url2" ] } } } ] }) { __typename refId url }
"errors": Array [
[GraphQLError: Field "url" is not defined by type "FilterFindManyEventOperatorsInput".],
],
Note: it has no knowledge of the "FilterFindManyClickedLinkEventOperatorsInput" as it has been overwritten by "FilterFindManyEventOperatorsInput"
The issue is with copyResolverArgTypes on ./src/discriminators/prepareChildResolvers.ts
for (const baseArgField of baseResolverArgTCFields) { if (childResolverArgTC.hasField(baseArgField) && baseArgField !== '_id') { childResolverArgTC.extendField(baseArgField, { type: baseResolverArgTC.getField(baseArgField).type, }); } }
It checks for '_id', but '_operators', 'AND' and 'OR' are extended overwriting the childResolver details.
I believe the fix is
@@ -85,7 +86,10 @@ function copyResolverArgTypes( const baseResolverArgTCFields = baseResolverArgTC.getFieldNames(); for (const baseArgField of baseResolverArgTCFields) { - if (childResolverArgTC.hasField(baseArgField) && baseArgField !== '_id') { + if ( + childResolverArgTC.hasField(baseArgField) && + ['_id', OPERATORS_FIELDNAME, 'OR', 'AND'].indexOf(baseArgField) === -1 + ) { childResolverArgTC.extendField(baseArgField, { type: baseResolverArgTC.getField(baseArgField).type, });
Integration test that produces the problem
Must have an index field to be included in _operators
const eventSchema = new mongoose.Schema( { refId: String, name: { type: String, index: true } }, options );
it('perform filter operation on a child model', async () => { // let's check graphql response await Event.deleteMany({}); await Event.create({ refId: 'aaa', name: 'aName' }); await Event.create({ refId: 'bbb', name: 'bName' }); await ClickedLinkEvent.create({ refId: 'ccc', name: 'cName', url: 'url1' }); await ClickedLinkEvent.create({ refId: 'ddd', name: 'dName', url: 'url2' }); schemaComposer.Query.addFields({ clickedLinkEventFindMany: ClickedLinkEventTC.getResolver('findMany'), }); const schema = schemaComposer.buildSchema(); const res = await graphql.graphql( schema, `{ clickedLinkEventFindMany( filter: { AND: [ { _operators: { url: { in: [ "url1", "url2" ] } } }, { name: "dName" } ] }) { __typename refId name url } }` ); expect(res).toEqual({ data: { clickedLinkEventFindMany: [ { __typename: 'ClickedLinkEvent', refId: 'ddd', name: 'dName', url: 'url2' }, ], }, }); });
A pull request will be made and the appropriate fix plus tests will be submitted for review.