Skip to content

Commit e0e9bbf

Browse files
committed
fix(type-merging): handle union types correctly
1 parent aba7e74 commit e0e9bbf

File tree

3 files changed

+117
-3
lines changed

3 files changed

+117
-3
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-tools/delegate': patch
3+
---
4+
5+
Handle type merging with union types correctly -> See https://github.com/ardatan/graphql-tools/issues/4902

packages/delegate/src/prepareGatewayDocument.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
visitWithTypeInfo,
1515
InlineFragmentNode,
1616
GraphQLOutputType,
17-
isObjectType,
17+
isCompositeType,
1818
FieldNode,
1919
} from 'graphql';
2020

@@ -382,7 +382,7 @@ function wrapConcreteTypes(
382382
): DocumentNode {
383383
const namedType = getNamedType(returnType);
384384

385-
if (!isObjectType(namedType)) {
385+
if (!isCompositeType(namedType)) {
386386
return document;
387387
}
388388

packages/stitch/tests/typeMerging.test.ts

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// The below is meant to be an alternative canonical schema stitching example
22
// which relies on type merging.
33

4-
import { graphql, OperationTypeNode } from 'graphql';
4+
import { graphql, OperationTypeNode, parse } from 'graphql';
55

66
import { makeExecutableSchema } from '@graphql-tools/schema';
77

@@ -13,6 +13,7 @@ import { RenameRootFields, RenameTypes } from '@graphql-tools/wrap';
1313
import { assertSome } from '@graphql-tools/utils';
1414

1515
import { stitchSchemas } from '../src/stitchSchemas.js';
16+
import { normalizedExecutor } from '@graphql-tools/executor';
1617

1718
describe('merging using type merging', () => {
1819
test('works', async () => {
@@ -552,6 +553,114 @@ describe('merging using type merging when renaming', () => {
552553
expect(userByIdData.chirps[1].text).not.toBe(null);
553554
expect(userByIdData.chirps[1].author.email).not.toBe(null);
554555
});
556+
it('union merge', async () => {
557+
const carVehicle = {
558+
id: '1',
559+
brand: 'Tesla',
560+
__typename: 'Car',
561+
};
562+
563+
const vehiclesSchema = makeExecutableSchema({
564+
typeDefs: /* GraphQL */ `
565+
type Query {
566+
getVehicle: Vehicle!
567+
}
568+
569+
union Vehicle = Car | Bike
570+
571+
type Car {
572+
id: ID!
573+
brand: String!
574+
}
575+
576+
type Bike {
577+
id: ID!
578+
brand: String!
579+
}
580+
`,
581+
resolvers: {
582+
Query: {
583+
getVehicle: () => carVehicle,
584+
},
585+
Vehicle: {
586+
__resolveType: () => 'Car',
587+
},
588+
},
589+
});
590+
const licensePlateSchema = makeExecutableSchema({
591+
typeDefs: /* GraphQL */ `
592+
scalar Any
593+
type Query {
594+
_entities(representations: [Any]!): [Entity]!
595+
}
596+
union Entity = Car
597+
type Car {
598+
id: ID!
599+
licensePlate: String!
600+
}
601+
`,
602+
resolvers: {
603+
Query: {
604+
_entities: (_, { representations }: { representations: any[] }) => representations,
605+
},
606+
Entity: {
607+
__resolveType: (root: any) => root.__typename,
608+
},
609+
Car: {
610+
licensePlate: () => 'ZH 1234',
611+
},
612+
},
613+
});
614+
const stitchedSchema = stitchSchemas({
615+
subschemas: [
616+
{
617+
schema: vehiclesSchema,
618+
merge: {
619+
Vehicle: {
620+
fieldName: 'getVehicle',
621+
selectionSet: '{ id }',
622+
key: representation => representation,
623+
argsFromKeys: representations => ({ representations }),
624+
},
625+
},
626+
},
627+
{
628+
schema: licensePlateSchema,
629+
merge: {
630+
Car: {
631+
fieldName: '_entities',
632+
selectionSet: '{ id }',
633+
key: representation => representation,
634+
argsFromKeys: representations => ({ representations }),
635+
},
636+
},
637+
},
638+
],
639+
});
640+
const result = await normalizedExecutor({
641+
schema: stitchedSchema,
642+
document: parse(/* GraphQL */ `
643+
{
644+
getVehicle {
645+
... on Car {
646+
id
647+
brand
648+
licensePlate ## 💥
649+
}
650+
}
651+
}
652+
`),
653+
});
654+
expect(result).toEqual({
655+
data: {
656+
getVehicle: {
657+
id: '1',
658+
brand: 'Tesla',
659+
licensePlate: 'ZH 1234',
660+
},
661+
},
662+
});
663+
});
555664
});
556665

557666
describe('external object annotation with batchDelegateToSchema', () => {

0 commit comments

Comments
 (0)