@@ -53,6 +53,7 @@ const deeperObject = new GraphQLObjectType({
53
53
const nestedObject = new GraphQLObjectType ( {
54
54
fields : {
55
55
deeperObject : { type : deeperObject , resolve : ( ) => ( { } ) } ,
56
+ name : { type : GraphQLString , resolve : ( ) => 'foo' } ,
56
57
} ,
57
58
name : 'NestedObject' ,
58
59
} ) ;
@@ -129,13 +130,29 @@ const heroType = new GraphQLObjectType({
129
130
type : new GraphQLList ( friendType ) ,
130
131
resolve : ( ) => friends ,
131
132
} ,
133
+ emptyFriends : {
134
+ type : new GraphQLList ( friendType ) ,
135
+ resolve : ( ) => [ ] ,
136
+ } ,
132
137
asyncFriends : {
133
138
type : new GraphQLList ( friendType ) ,
134
139
async * resolve ( ) {
135
140
yield await Promise . resolve ( friends [ 0 ] ) ;
136
141
} ,
137
142
} ,
143
+ asyncEmptyFriends : {
144
+ type : new GraphQLList ( friendType ) ,
145
+ // eslint-disable-next-line require-yield
146
+ async * resolve ( ) {
147
+ await resolveOnNextTick ( ) ;
148
+ } ,
149
+ } ,
138
150
nestedObject : { type : nestedObject , resolve : ( ) => ( { } ) } ,
151
+ promiseNestedObject : {
152
+ type : nestedObject ,
153
+ resolve : ( ) => Promise . resolve ( { } ) ,
154
+ } ,
155
+ nullNestedObject : { type : nestedObject , resolve : ( ) => null } ,
139
156
anotherNestedObject : { type : anotherNestedObject , resolve : ( ) => ( { } ) } ,
140
157
} ,
141
158
name : 'Hero' ,
@@ -395,26 +412,14 @@ describe('Execute: defer directive', () => {
395
412
}
396
413
` ) ;
397
414
const result = await complete ( document ) ;
398
- expectJSON ( result ) . toDeepEqual ( [
399
- {
400
- data : {
401
- hero : {
402
- id : '1' ,
403
- name : 'Luke' ,
404
- } ,
415
+ expectJSON ( result ) . toDeepEqual ( {
416
+ data : {
417
+ hero : {
418
+ id : '1' ,
419
+ name : 'Luke' ,
405
420
} ,
406
- hasNext : true ,
407
421
} ,
408
- {
409
- incremental : [
410
- {
411
- data : { } ,
412
- path : [ 'hero' ] ,
413
- } ,
414
- ] ,
415
- hasNext : false ,
416
- } ,
417
- ] ) ;
422
+ } ) ;
418
423
} ) ;
419
424
it ( 'Can defer a fragment that is also not deferred, non-deferred fragment is first' , async ( ) => {
420
425
const document = parse ( `
@@ -430,26 +435,14 @@ describe('Execute: defer directive', () => {
430
435
}
431
436
` ) ;
432
437
const result = await complete ( document ) ;
433
- expectJSON ( result ) . toDeepEqual ( [
434
- {
435
- data : {
436
- hero : {
437
- id : '1' ,
438
- name : 'Luke' ,
439
- } ,
438
+ expectJSON ( result ) . toDeepEqual ( {
439
+ data : {
440
+ hero : {
441
+ id : '1' ,
442
+ name : 'Luke' ,
440
443
} ,
441
- hasNext : true ,
442
- } ,
443
- {
444
- incremental : [
445
- {
446
- data : { } ,
447
- path : [ 'hero' ] ,
448
- } ,
449
- ] ,
450
- hasNext : false ,
451
444
} ,
452
- ] ) ;
445
+ } ) ;
453
446
} ) ;
454
447
455
448
it ( 'Can defer an inline fragment' , async ( ) => {
@@ -578,9 +571,6 @@ describe('Execute: defer directive', () => {
578
571
bar : 'bar' ,
579
572
} ,
580
573
} ,
581
- anotherNestedObject : {
582
- deeperObject : { } ,
583
- } ,
584
574
} ,
585
575
path : [ 'hero' ] ,
586
576
} ,
@@ -772,14 +762,6 @@ describe('Execute: defer directive', () => {
772
762
} ,
773
763
path : [ 'hero' , 'nestedObject' , 'deeperObject' ] ,
774
764
} ,
775
- {
776
- data : {
777
- nestedObject : {
778
- deeperObject : { } ,
779
- } ,
780
- } ,
781
- path : [ 'hero' ] ,
782
- } ,
783
765
] ,
784
766
hasNext : false ,
785
767
} ,
@@ -860,6 +842,176 @@ describe('Execute: defer directive', () => {
860
842
] ) ;
861
843
} ) ;
862
844
845
+ it ( 'Can deduplicate list fields' , async ( ) => {
846
+ const document = parse ( `
847
+ query {
848
+ hero {
849
+ friends {
850
+ name
851
+ }
852
+ ... @defer {
853
+ friends {
854
+ name
855
+ }
856
+ }
857
+ }
858
+ }
859
+ ` ) ;
860
+ const result = await complete ( document ) ;
861
+ expectJSON ( result ) . toDeepEqual ( {
862
+ data : {
863
+ hero : {
864
+ friends : [ { name : 'Han' } , { name : 'Leia' } , { name : 'C-3PO' } ] ,
865
+ } ,
866
+ } ,
867
+ } ) ;
868
+ } ) ;
869
+
870
+ it ( 'Can deduplicate async iterable list fields' , async ( ) => {
871
+ const document = parse ( `
872
+ query {
873
+ hero {
874
+ asyncFriends {
875
+ name
876
+ }
877
+ ... @defer {
878
+ asyncFriends {
879
+ name
880
+ }
881
+ }
882
+ }
883
+ }
884
+ ` ) ;
885
+ const result = await complete ( document ) ;
886
+ expectJSON ( result ) . toDeepEqual ( {
887
+ data : { hero : { asyncFriends : [ { name : 'Han' } ] } } ,
888
+ } ) ;
889
+ } ) ;
890
+
891
+ it ( 'Can deduplicate empty async iterable list fields' , async ( ) => {
892
+ const document = parse ( `
893
+ query {
894
+ hero {
895
+ asyncEmptyFriends {
896
+ name
897
+ }
898
+ ... @defer {
899
+ asyncEmptyFriends {
900
+ name
901
+ }
902
+ }
903
+ }
904
+ }
905
+ ` ) ;
906
+ const result = await complete ( document ) ;
907
+ expectJSON ( result ) . toDeepEqual ( {
908
+ data : { hero : { asyncEmptyFriends : [ ] } } ,
909
+ } ) ;
910
+ } ) ;
911
+
912
+ it ( "Doesn't deduplicate list fields with non-overlapping fields" , async ( ) => {
913
+ const document = parse ( `
914
+ query {
915
+ hero {
916
+ friends {
917
+ name
918
+ }
919
+ ... @defer {
920
+ friends {
921
+ name
922
+ id
923
+ }
924
+ }
925
+ }
926
+ }
927
+ ` ) ;
928
+ const result = await complete ( document ) ;
929
+ expectJSON ( result ) . toDeepEqual ( [
930
+ {
931
+ data : {
932
+ hero : {
933
+ friends : [ { name : 'Han' } , { name : 'Leia' } , { name : 'C-3PO' } ] ,
934
+ } ,
935
+ } ,
936
+ hasNext : true ,
937
+ } ,
938
+ {
939
+ incremental : [
940
+ {
941
+ data : {
942
+ friends : [ { id : '2' } , { id : '3' } , { id : '4' } ] ,
943
+ } ,
944
+ path : [ 'hero' ] ,
945
+ } ,
946
+ ] ,
947
+ hasNext : false ,
948
+ } ,
949
+ ] ) ;
950
+ } ) ;
951
+
952
+ it ( 'Can deduplicate list fields that return empty lists' , async ( ) => {
953
+ const document = parse ( `
954
+ query {
955
+ hero {
956
+ emptyFriends {
957
+ name
958
+ }
959
+ ... @defer {
960
+ emptyFriends {
961
+ name
962
+ }
963
+ }
964
+ }
965
+ }
966
+ ` ) ;
967
+ const result = await complete ( document ) ;
968
+ expectJSON ( result ) . toDeepEqual ( {
969
+ data : { hero : { emptyFriends : [ ] } } ,
970
+ } ) ;
971
+ } ) ;
972
+
973
+ it ( 'Can deduplicate null object fields' , async ( ) => {
974
+ const document = parse ( `
975
+ query {
976
+ hero {
977
+ nullNestedObject {
978
+ name
979
+ }
980
+ ... @defer {
981
+ nullNestedObject {
982
+ name
983
+ }
984
+ }
985
+ }
986
+ }
987
+ ` ) ;
988
+ const result = await complete ( document ) ;
989
+ expectJSON ( result ) . toDeepEqual ( {
990
+ data : { hero : { nullNestedObject : null } } ,
991
+ } ) ;
992
+ } ) ;
993
+
994
+ it ( 'Can deduplicate promise object fields' , async ( ) => {
995
+ const document = parse ( `
996
+ query {
997
+ hero {
998
+ promiseNestedObject {
999
+ name
1000
+ }
1001
+ ... @defer {
1002
+ promiseNestedObject {
1003
+ name
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ ` ) ;
1009
+ const result = await complete ( document ) ;
1010
+ expectJSON ( result ) . toDeepEqual ( {
1011
+ data : { hero : { promiseNestedObject : { name : 'foo' } } } ,
1012
+ } ) ;
1013
+ } ) ;
1014
+
863
1015
it ( 'Handles errors thrown in deferred fragments' , async ( ) => {
864
1016
const document = parse ( `
865
1017
query HeroNameQuery {
0 commit comments