@@ -5,6 +5,7 @@ import { parse } from '../../language/parser';
5
5
6
6
import {
7
7
GraphQLInterfaceType ,
8
+ GraphQLIntersectionType ,
8
9
GraphQLList ,
9
10
GraphQLObjectType ,
10
11
GraphQLUnionType ,
@@ -45,15 +46,18 @@ class Cat {
45
46
class Person {
46
47
name : string ;
47
48
pets ?: ReadonlyArray < Dog | Cat > ;
48
- friends ?: ReadonlyArray < Dog | Cat | Person > ;
49
+ mammalPets ?: ReadonlyArray < Dog | Cat > ;
50
+ friends ?: ReadonlyArray < Dog | Person > ;
49
51
50
52
constructor (
51
53
name : string ,
52
54
pets ?: ReadonlyArray < Dog | Cat > ,
55
+ mammalPets ?: ReadonlyArray < Dog | Cat > ,
53
56
friends ?: ReadonlyArray < Dog | Cat | Person > ,
54
57
) {
55
58
this . name = name ;
56
59
this . pets = pets ;
60
+ this . mammalPets = mammalPets ;
57
61
this . friends = friends ;
58
62
}
59
63
}
@@ -130,6 +134,7 @@ const PersonType: GraphQLObjectType = new GraphQLObjectType({
130
134
fields : ( ) => ( {
131
135
name : { type : GraphQLString } ,
132
136
pets : { type : new GraphQLList ( PetType ) } ,
137
+ mammalPets : { type : new GraphQLList ( MammalPetType ) } ,
133
138
friends : { type : new GraphQLList ( NamedType ) } ,
134
139
progeny : { type : new GraphQLList ( PersonType ) } ,
135
140
mother : { type : PersonType } ,
@@ -138,6 +143,22 @@ const PersonType: GraphQLObjectType = new GraphQLObjectType({
138
143
isTypeOf : ( value ) => value instanceof Person ,
139
144
} ) ;
140
145
146
+ const MammalPetType = new GraphQLIntersectionType ( {
147
+ name : 'MammalPet' ,
148
+ types : [ PetType , MammalType ] ,
149
+ resolveType ( value ) {
150
+ if ( value instanceof Dog ) {
151
+ return DogType . name ;
152
+ }
153
+ if ( value instanceof Cat ) {
154
+ return CatType . name ;
155
+ }
156
+ /* c8 ignore next 3 */
157
+ // Not reachable, all possible types have been considered.
158
+ expect . fail ( 'Not reachable' ) ;
159
+ } ,
160
+ } ) ;
161
+
141
162
const schema = new GraphQLSchema ( {
142
163
query : PersonType ,
143
164
types : [ PetType ] ,
@@ -152,17 +173,23 @@ odie.mother = new Dog("Odie's Mom", true);
152
173
odie . mother . progeny = [ odie ] ;
153
174
154
175
const liz = new Person ( 'Liz' ) ;
155
- const john = new Person ( 'John' , [ garfield , odie ] , [ liz , odie ] ) ;
156
-
157
- describe ( 'Execute: Union and intersection types' , ( ) => {
158
- it ( 'can introspect on union and intersection types' , ( ) => {
176
+ const john = new Person (
177
+ 'John' ,
178
+ [ garfield , odie ] ,
179
+ [ garfield , odie ] ,
180
+ [ liz , odie ] ,
181
+ ) ;
182
+
183
+ describe ( 'Execute: Union, interface and intersection types' , ( ) => {
184
+ it ( 'can introspect on union, interface and intersection types' , ( ) => {
159
185
const document = parse ( `
160
186
{
161
187
Named: __type(name: "Named") {
162
188
kind
163
189
name
164
190
fields { name }
165
191
interfaces { name }
192
+ memberTypes { name }
166
193
possibleTypes { name }
167
194
enumValues { name }
168
195
inputFields { name }
@@ -172,6 +199,7 @@ describe('Execute: Union and intersection types', () => {
172
199
name
173
200
fields { name }
174
201
interfaces { name }
202
+ memberTypes { name }
175
203
possibleTypes { name }
176
204
enumValues { name }
177
205
inputFields { name }
@@ -181,6 +209,17 @@ describe('Execute: Union and intersection types', () => {
181
209
name
182
210
fields { name }
183
211
interfaces { name }
212
+ memberTypes { name }
213
+ possibleTypes { name }
214
+ enumValues { name }
215
+ inputFields { name }
216
+ }
217
+ MammalPet: __type(name: "MammalPet") {
218
+ kind
219
+ name
220
+ fields { name }
221
+ interfaces { name }
222
+ memberTypes { name }
184
223
possibleTypes { name }
185
224
enumValues { name }
186
225
inputFields { name }
@@ -195,6 +234,7 @@ describe('Execute: Union and intersection types', () => {
195
234
name : 'Named' ,
196
235
fields : [ { name : 'name' } ] ,
197
236
interfaces : [ ] ,
237
+ memberTypes : null ,
198
238
possibleTypes : [ { name : 'Dog' } , { name : 'Cat' } , { name : 'Person' } ] ,
199
239
enumValues : null ,
200
240
inputFields : null ,
@@ -204,6 +244,7 @@ describe('Execute: Union and intersection types', () => {
204
244
name : 'Mammal' ,
205
245
fields : [ { name : 'progeny' } , { name : 'mother' } , { name : 'father' } ] ,
206
246
interfaces : [ { name : 'Life' } ] ,
247
+ memberTypes : null ,
207
248
possibleTypes : [ { name : 'Dog' } , { name : 'Cat' } , { name : 'Person' } ] ,
208
249
enumValues : null ,
209
250
inputFields : null ,
@@ -213,6 +254,17 @@ describe('Execute: Union and intersection types', () => {
213
254
name : 'Pet' ,
214
255
fields : null ,
215
256
interfaces : null ,
257
+ memberTypes : null ,
258
+ possibleTypes : [ { name : 'Dog' } , { name : 'Cat' } ] ,
259
+ enumValues : null ,
260
+ inputFields : null ,
261
+ } ,
262
+ MammalPet : {
263
+ kind : 'INTERSECTION' ,
264
+ name : 'MammalPet' ,
265
+ fields : null ,
266
+ interfaces : null ,
267
+ memberTypes : [ { name : 'Pet' } , { name : 'Mammal' } ] ,
216
268
possibleTypes : [ { name : 'Dog' } , { name : 'Cat' } ] ,
217
269
enumValues : null ,
218
270
inputFields : null ,
@@ -418,12 +470,152 @@ describe('Execute: Union and intersection types', () => {
418
470
} ) ;
419
471
} ) ;
420
472
473
+ it ( 'executes using intersection types' , ( ) => {
474
+ // NOTE: This is an *invalid* query, but it should be an *executable* query.
475
+ const document = parse ( `
476
+ {
477
+ __typename
478
+ name
479
+ mammalPets {
480
+ __typename
481
+ name
482
+ barks
483
+ meows
484
+ }
485
+ }
486
+ ` ) ;
487
+
488
+ expect ( executeSync ( { schema, document, rootValue : john } ) ) . to . deep . equal ( {
489
+ data : {
490
+ __typename : 'Person' ,
491
+ name : 'John' ,
492
+ mammalPets : [
493
+ { __typename : 'Cat' , name : 'Garfield' , meows : false } ,
494
+ { __typename : 'Dog' , name : 'Odie' , barks : true } ,
495
+ ] ,
496
+ } ,
497
+ } ) ;
498
+ } ) ;
499
+
500
+ it ( 'executes intersection types with inline fragments' , ( ) => {
501
+ // This is the valid version of the query in the above test.
502
+ const document = parse ( `
503
+ {
504
+ __typename
505
+ name
506
+ mammalPets {
507
+ __typename
508
+ name
509
+ ... on Dog {
510
+ barks
511
+ }
512
+ ... on Cat {
513
+ meows
514
+ }
515
+
516
+ ... on Mammal {
517
+ mother {
518
+ __typename
519
+ ... on Dog {
520
+ name
521
+ barks
522
+ }
523
+ ... on Cat {
524
+ name
525
+ meows
526
+ }
527
+ }
528
+ }
529
+ }
530
+ }
531
+ ` ) ;
532
+
533
+ expect ( executeSync ( { schema, document, rootValue : john } ) ) . to . deep . equal ( {
534
+ data : {
535
+ __typename : 'Person' ,
536
+ name : 'John' ,
537
+ mammalPets : [
538
+ {
539
+ __typename : 'Cat' ,
540
+ name : 'Garfield' ,
541
+ meows : false ,
542
+ mother : {
543
+ __typename : 'Cat' ,
544
+ name : "Garfield's Mom" ,
545
+ meows : false ,
546
+ } ,
547
+ } ,
548
+ {
549
+ __typename : 'Dog' ,
550
+ name : 'Odie' ,
551
+ barks : true ,
552
+ mother : {
553
+ __typename : 'Dog' ,
554
+ name : "Odie's Mom" ,
555
+ barks : true ,
556
+ } ,
557
+ } ,
558
+ ] ,
559
+ } ,
560
+ } ) ;
561
+ } ) ;
562
+
563
+ it ( 'executes intersection types with named fragments' , ( ) => {
564
+ const document = parse ( `
565
+ {
566
+ __typename
567
+ name
568
+ mammalPets {
569
+ __typename
570
+ name
571
+ ...DogBarks
572
+ ...CatMeows
573
+ }
574
+ }
575
+
576
+ fragment DogBarks on Dog {
577
+ barks
578
+ }
579
+
580
+ fragment CatMeows on Cat {
581
+ meows
582
+ }
583
+ ` ) ;
584
+
585
+ expect ( executeSync ( { schema, document, rootValue : john } ) ) . to . deep . equal ( {
586
+ data : {
587
+ __typename : 'Person' ,
588
+ name : 'John' ,
589
+ mammalPets : [
590
+ {
591
+ __typename : 'Cat' ,
592
+ name : 'Garfield' ,
593
+ meows : false ,
594
+ } ,
595
+ {
596
+ __typename : 'Dog' ,
597
+ name : 'Odie' ,
598
+ barks : true ,
599
+ } ,
600
+ ] ,
601
+ } ,
602
+ } ) ;
603
+ } ) ;
604
+
421
605
it ( 'allows fragment conditions to be abstract types' , ( ) => {
422
606
const document = parse ( `
423
607
{
424
608
__typename
425
609
name
426
610
pets {
611
+ ...MammalPetFields,
612
+ ...on Mammal {
613
+ mother {
614
+ ...ProgenyFields
615
+ }
616
+ }
617
+ }
618
+ mammalPets {
427
619
...PetFields,
428
620
...on Mammal {
429
621
mother {
@@ -434,6 +626,18 @@ describe('Execute: Union and intersection types', () => {
434
626
friends { ...FriendFields }
435
627
}
436
628
629
+ fragment MammalPetFields on Pet {
630
+ __typename
631
+ ... on Dog {
632
+ name
633
+ barks
634
+ }
635
+ ... on Cat {
636
+ name
637
+ meows
638
+ }
639
+ }
640
+
437
641
fragment PetFields on Pet {
438
642
__typename
439
643
... on Dog {
@@ -482,6 +686,20 @@ describe('Execute: Union and intersection types', () => {
482
686
mother : { progeny : [ { __typename : 'Dog' } ] } ,
483
687
} ,
484
688
] ,
689
+ mammalPets : [
690
+ {
691
+ __typename : 'Cat' ,
692
+ name : 'Garfield' ,
693
+ meows : false ,
694
+ mother : { progeny : [ { __typename : 'Cat' } ] } ,
695
+ } ,
696
+ {
697
+ __typename : 'Dog' ,
698
+ name : 'Odie' ,
699
+ barks : true ,
700
+ mother : { progeny : [ { __typename : 'Dog' } ] } ,
701
+ } ,
702
+ ] ,
485
703
friends : [
486
704
{
487
705
__typename : 'Person' ,
@@ -525,7 +743,7 @@ describe('Execute: Union and intersection types', () => {
525
743
} ) ;
526
744
const schema2 = new GraphQLSchema ( { query : PersonType2 } ) ;
527
745
const document = parse ( '{ name, friends { name } }' ) ;
528
- const rootValue = new Person ( 'John' , [ ] , [ liz ] ) ;
746
+ const rootValue = new Person ( 'John' , [ ] , [ ] , [ liz ] ) ;
529
747
const contextValue = { authToken : '123abc' } ;
530
748
531
749
const result = executeSync ( {
0 commit comments