Skip to content

Fields on _operators are lost on child resolvers when using discriminators #390

Open
@tatejones

Description

@tatejones

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions