From 56a7e5a87ce01ab592877283ecd0ab32bcace121 Mon Sep 17 00:00:00 2001 From: Felipe Bergamin Date: Wed, 4 Oct 2023 09:59:50 -0300 Subject: [PATCH] fix: directives running twice when used on Query and Mutation --- lib/createSchemaMapperForVisitor.ts | 10 +++++- lib/foreignNodeId.test.ts | 56 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/createSchemaMapperForVisitor.ts b/lib/createSchemaMapperForVisitor.ts index 72efdbc..272f91e 100644 --- a/lib/createSchemaMapperForVisitor.ts +++ b/lib/createSchemaMapperForVisitor.ts @@ -63,7 +63,15 @@ export const createSchemaMapperForVisitor = visitor: EasyDirectiveVisitor, ): SchemaMapperFunction => (unmappedSchema: GraphQLSchema): GraphQLSchema => { - return mapSchema(unmappedSchema, createMapper(directiveName, visitor)); + const { 'MapperKind.MUTATION': mutationMapper, ...mappers } = createMapper( + directiveName, + visitor, + ); + const mappedSchema = mapSchema(unmappedSchema, mappers); + // run mutation mapper separately toa void conflicts with Query mapper adding validation functions to schema object + return mapSchema(mappedSchema, { + [MapperKind.MUTATION]: mutationMapper, + }); }; export default createSchemaMapperForVisitor; diff --git a/lib/foreignNodeId.test.ts b/lib/foreignNodeId.test.ts index ad588be..eeabb6f 100644 --- a/lib/foreignNodeId.test.ts +++ b/lib/foreignNodeId.test.ts @@ -318,4 +318,60 @@ ${validationDirectionEnumTypeDefs(capitalizedName)} expect.any(Object), ); }); + + it('should not duplicate validation when same type is used on Query and Mutation', async () => { + const mockResolver = jest.fn().mockReturnValue('return value'); + const typeName = 'MyType'; + const decodedId = 'abc'; + const encodedId = toNodeId('MyType', decodedId); + const schema = new ForeignNodeId().applyToSchema( + makeExecutableSchema({ + resolvers: { + Mutation: { + testDirective: mockResolver, + }, + Query: { + dummy: () => '', + }, + }, + typeDefs: [ + ...directiveTypeDefs, + gql` + input Input1 { + typeId: ID! @foreignNodeId(typename: "${typeName}") + } + type Query { + dummy(input: Input1): String + } + type Mutation { + testDirective(input: Input1): String + } + `, + ], + }), + ); + const source = print(gql` + mutation Testing($input: Input1!) { + testDirective(input: $input) + } + `); + const contextValue = ForeignNodeId.createDirectiveContext({ + fromNodeId, + }); + const fromNodeIdSpy = jest.spyOn(contextValue, 'fromNodeId'); + + await graphql({ + contextValue, + schema, + source, + variableValues: { + input: { + typeId: encodedId, + }, + }, + }); + + expect(fromNodeIdSpy).toHaveBeenCalledTimes(1); + expect(fromNodeIdSpy).toHaveBeenCalledWith(encodedId); + }); });