Skip to content

Commit 037a451

Browse files
committed
introduce new Intersection type
Intersections of unions and interfaces can be considered to "implement" their unions and interface members. A type with a field of type Intersection will satisfy an interface where the field defined in the interface is one of the member types of the intersection. Alternative to #3527
1 parent 5ccf579 commit 037a451

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2847
-56
lines changed

docs-old/APIReference-GraphQL.md

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ _Type Definitions_
6666
A union type within GraphQL that defines a list of implementations.
6767
</a>
6868
</li>
69+
<li>
70+
<a href="../type/#graphqlintersectiontype">
71+
<pre>class GraphQLIntersectionType</pre>
72+
An intersection type within GraphQL that defines a list of constraining types.
73+
</a>
74+
</li>
6975
<li>
7076
<a href="../type/#graphqlenumtype">
7177
<pre>class GraphQLEnumType</pre>

docs-old/APIReference-TypeSystem.md

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ _Definitions_
5454
A union type within GraphQL that defines a list of implementations.
5555
</a>
5656
</li>
57+
<li>
58+
<a href="#graphqlintersectiontype">
59+
<pre>class GraphQLIntersectionType</pre>
60+
An intersection type within GraphQL that defines a list of constraining types.
61+
</a>
62+
</li>
5763
<li>
5864
<a href="#graphqlenumtype">
5965
<pre>class GraphQLEnumType</pre>

src/__testUtils__/kitchenSinkSDL.ts

+12
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ extend union Feed = Photo | Video
7979
8080
extend union Feed @onUnion
8181
82+
intersection Resource = Feed & Node
83+
84+
intersection AnnotatedIntersection @onIntersection = Feed & Node
85+
86+
intersection AnnotatedIntersectionTwo @onIntersection = Feed & Node
87+
88+
intersection UndefinedIntersection
89+
90+
extend intersection Resource = Media & Accessible
91+
92+
extend intersection Resource @onIntersection
93+
8294
scalar CustomScalar
8395
8496
scalar AnnotatedScalar @onScalar

src/execution/__tests__/abstract-test.ts

+161
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { parse } from '../../language/parser';
88
import {
99
assertInterfaceType,
1010
GraphQLInterfaceType,
11+
GraphQLIntersectionType,
1112
GraphQLList,
1213
GraphQLObjectType,
1314
GraphQLUnionType,
@@ -352,6 +353,94 @@ describe('Execute: Handles execution of abstract types', () => {
352353
});
353354
});
354355

356+
it('isTypeOf used to resolve runtime type for Intersection', async () => {
357+
const DogType = new GraphQLObjectType({
358+
name: 'Dog',
359+
isTypeOf(obj, context) {
360+
const isDog = obj instanceof Dog;
361+
return context.async ? Promise.resolve(isDog) : isDog;
362+
},
363+
interfaces: () => [PetType],
364+
fields: {
365+
name: { type: GraphQLString },
366+
woofs: { type: GraphQLBoolean },
367+
},
368+
});
369+
370+
const CatType = new GraphQLObjectType({
371+
name: 'Cat',
372+
isTypeOf(obj, context) {
373+
const isCat = obj instanceof Cat;
374+
return context.async ? Promise.resolve(isCat) : isCat;
375+
},
376+
interfaces: () => [PetType],
377+
fields: {
378+
name: { type: GraphQLString },
379+
meows: { type: GraphQLBoolean },
380+
},
381+
});
382+
383+
const PetType = new GraphQLInterfaceType({
384+
name: 'Pet',
385+
fields: {
386+
name: { type: GraphQLString },
387+
},
388+
});
389+
390+
const CatOrDogType = new GraphQLUnionType({
391+
name: 'CatOrDog',
392+
types: [DogType, CatType],
393+
});
394+
395+
const CatOrDogPetType = new GraphQLIntersectionType({
396+
name: 'CatOrDogPet',
397+
types: [CatOrDogType, PetType],
398+
});
399+
400+
const schema = new GraphQLSchema({
401+
query: new GraphQLObjectType({
402+
name: 'Query',
403+
fields: {
404+
catOrDogPets: {
405+
type: new GraphQLList(CatOrDogPetType),
406+
resolve() {
407+
return [new Dog('Odie', true), new Cat('Garfield', false)];
408+
},
409+
},
410+
},
411+
}),
412+
});
413+
414+
const query = `{
415+
catOrDogPets {
416+
... on Pet {
417+
name
418+
}
419+
... on Dog {
420+
woofs
421+
}
422+
... on Cat {
423+
meows
424+
}
425+
}
426+
}`;
427+
428+
expect(await executeQuery({ schema, query })).to.deep.equal({
429+
data: {
430+
catOrDogPets: [
431+
{
432+
name: 'Odie',
433+
woofs: true,
434+
},
435+
{
436+
name: 'Garfield',
437+
meows: false,
438+
},
439+
],
440+
},
441+
});
442+
});
443+
355444
it('resolveType can throw', async () => {
356445
const PetType = new GraphQLInterfaceType({
357446
name: 'Pet',
@@ -497,6 +586,78 @@ describe('Execute: Handles execution of abstract types', () => {
497586
});
498587
});
499588

589+
it('resolve Intersection type using __typename on source object', async () => {
590+
const schema = buildSchema(`
591+
type Query {
592+
catOrDogPets: [CatOrDogPet]
593+
}
594+
595+
union CatOrDog = Cat | Dog
596+
597+
interface Pet {
598+
name: String
599+
}
600+
601+
intersection CatOrDogPet = CatOrDog & Pet
602+
603+
type Cat implements Pet {
604+
name: String
605+
meows: Boolean
606+
}
607+
608+
type Dog implements Pet {
609+
name: String
610+
woofs: Boolean
611+
}
612+
`);
613+
614+
const query = `
615+
{
616+
catOrDogPets {
617+
... on Pet {
618+
name
619+
}
620+
... on Dog {
621+
woofs
622+
}
623+
... on Cat {
624+
meows
625+
}
626+
}
627+
}
628+
`;
629+
630+
const rootValue = {
631+
catOrDogPets: [
632+
{
633+
__typename: 'Dog',
634+
name: 'Odie',
635+
woofs: true,
636+
},
637+
{
638+
__typename: 'Cat',
639+
name: 'Garfield',
640+
meows: false,
641+
},
642+
],
643+
};
644+
645+
expect(await executeQuery({ schema, query, rootValue })).to.deep.equal({
646+
data: {
647+
catOrDogPets: [
648+
{
649+
name: 'Odie',
650+
woofs: true,
651+
},
652+
{
653+
name: 'Garfield',
654+
meows: false,
655+
},
656+
],
657+
},
658+
});
659+
});
660+
500661
it('resolve Interface type using __typename on source object', async () => {
501662
const schema = buildSchema(`
502663
type Query {

0 commit comments

Comments
 (0)