diff --git a/packages/stitch/src/createMergedTypeResolver.ts b/packages/stitch/src/createMergedTypeResolver.ts index 351934fb5ab..0293ea5a3f4 100644 --- a/packages/stitch/src/createMergedTypeResolver.ts +++ b/packages/stitch/src/createMergedTypeResolver.ts @@ -19,7 +19,7 @@ export function createMergedTypeResolver = ) { return batchDelegateToSchema({ schema: subschema, - operation: 'query' as OperationTypeNode, + operation: info.operation.operation as OperationTypeNode, fieldName, returnType: new GraphQLList(type), key, @@ -45,7 +45,7 @@ export function createMergedTypeResolver = ) { return delegateToSchema({ schema: subschema, - operation: 'query' as OperationTypeNode, + operation: info.operation.operation as OperationTypeNode, fieldName, returnType: type, args: args(originalResult), diff --git a/packages/stitch/tests/stitchMutationSchema.ts b/packages/stitch/tests/stitchMutationSchema.ts new file mode 100644 index 00000000000..7c9da973e6d --- /dev/null +++ b/packages/stitch/tests/stitchMutationSchema.ts @@ -0,0 +1,248 @@ +import { makeExecutableSchema } from '@graphql-tools/schema'; +import { stitchSchemas } from '../src/stitchSchemas.js'; +import { graphql } from 'graphql'; +import { assertSome } from '@graphql-tools/utils'; + +describe('Mutations executed as mutation on stitched schema', () => { + test('Mutation executed when only mutation type is available', async () => { + const sub0Schema = makeExecutableSchema({ + typeDefs: /* GraphQL */ ` + type Query { + placeholder: Placeholder + } + type Placeholder { + id: ID! + } + type Mutation { + zeroUser(id: ID): User + } + type User { + id: ID! + zeroValue: String + user: User! + } + `, + resolvers: { + Mutation: { + zeroUser: (_p, { id }) => ({ id }), + }, + User: { + zeroValue: (_p, _a, _c, i) => `0: User: ${i.operation.operation}`, + user: ({ id }) => ({ id }), + }, + }, + }); + + const sub1Schema = makeExecutableSchema({ + typeDefs: /* GraphQL */ ` + type Query { + placeholder: Placeholder + } + type Placeholder { + id: ID! + } + type Mutation { + oneUser(id: ID): User + } + type User { + id: ID! + oneValue: String + user: User! + } + `, + resolvers: { + Mutation: { + oneUser: (_p, { id }) => ({ id }), + }, + User: { + oneValue: (_p, _a, _c, i) => `1: User: ${i.operation.operation}`, + user: ({ id }) => ({ id }), + }, + }, + }); + const mergedSchema = stitchSchemas({ + subschemas: [ + { + schema: sub1Schema, + merge: { + User: { + fieldName: 'oneUser', + selectionSet: '{ id }', + args: o => ({ id: o.id }), + }, + }, + }, + { + schema: sub0Schema, + merge: { + User: { + fieldName: 'zeroUser', + selectionSet: '{ id }', + args: o => ({ id: o.id }), + }, + }, + }, + ], + mergeTypes: true, // << default in v7 + }); + const { data } = await graphql({ + schema: mergedSchema, + source: /* GraphQL */ ` + mutation { + # or oneUser, which zeroValue becomes null + zeroUser(id: 1) { + __typename + id + zeroValue + oneValue + user { + __typename + id + zeroValue + oneValue + } + } + } + `, + }); + assertSome(data); + const userData: any = data['zeroUser']; + expect(userData).toEqual({ + __typename: 'User', + id: '1', + oneValue: '1: User: mutation', + zeroValue: '0: User: mutation', + user: { + __typename: 'User', + id: '1', + oneValue: '1: User: mutation', + zeroValue: '0: User: mutation', + }, + }); + }); + + test('Mutation executed when both mutation and query are available', async () => { + const sub0Schema = makeExecutableSchema({ + typeDefs: /* GraphQL */ ` + type Query { + placeholder: Placeholder + zeroUser(id: ID): User + } + type Placeholder { + id: ID! + } + type Mutation { + zeroUser(id: ID): User + } + type User { + id: ID! + zeroValue: String + user: User! + } + `, + resolvers: { + Query: { + zeroUser: (_p, { id }) => ({ id }), + }, + Mutation: { + zeroUser: (_p, { id }) => ({ id }), + }, + User: { + zeroValue: (_p, _a, _c, i) => `0: User: ${i.operation.operation}`, + user: ({ id }) => ({ id }), + }, + }, + }); + + const sub1Schema = makeExecutableSchema({ + typeDefs: /* GraphQL */ ` + type Query { + placeholder: Placeholder + oneUser(id: ID): User + } + type Placeholder { + id: ID! + } + type Mutation { + oneUser(id: ID): User + } + type User { + id: ID! + oneValue: String + user: User! + } + `, + resolvers: { + Query: { + oneUser: (_p, { id }) => ({ id }), + }, + Mutation: { + oneUser: (_p, { id }) => ({ id }), + }, + User: { + oneValue: (_p, _a, _c, i) => `1: User: ${i.operation.operation}`, + user: ({ id }) => ({ id }), + }, + }, + }); + const mergedSchema = stitchSchemas({ + subschemas: [ + { + schema: sub1Schema, + merge: { + User: { + fieldName: 'oneUser', + selectionSet: '{ id }', + args: o => ({ id: o.id }), + }, + }, + }, + { + schema: sub0Schema, + merge: { + User: { + fieldName: 'zeroUser', + selectionSet: '{ id }', + args: o => ({ id: o.id }), + }, + }, + }, + ], + mergeTypes: true, // << default in v7 + }); + const { data } = await graphql({ + schema: mergedSchema, + source: /* GraphQL */ ` + mutation { + # or oneUser, which zeroValue becomes null + zeroUser(id: 1) { + __typename + id + zeroValue + oneValue + user { + __typename + id + zeroValue + oneValue + } + } + } + `, + }); + assertSome(data); + const userData: any = data['zeroUser']; + expect(userData).toEqual({ + __typename: 'User', + id: '1', + oneValue: '1: User: mutation', + zeroValue: '0: User: mutation', + user: { + __typename: 'User', + id: '1', + oneValue: '1: User: mutation', + zeroValue: '0: User: mutation', + }, + }); + }); +});