@@ -53,6 +53,7 @@ const deeperObject = new GraphQLObjectType({
5353const nestedObject = new GraphQLObjectType ( {
5454 fields : {
5555 deeperObject : { type : deeperObject , resolve : ( ) => ( { } ) } ,
56+ name : { type : GraphQLString , resolve : ( ) => 'foo' } ,
5657 } ,
5758 name : 'NestedObject' ,
5859} ) ;
@@ -129,13 +130,29 @@ const heroType = new GraphQLObjectType({
129130 type : new GraphQLList ( friendType ) ,
130131 resolve : ( ) => friends ,
131132 } ,
133+ emptyFriends : {
134+ type : new GraphQLList ( friendType ) ,
135+ resolve : ( ) => [ ] ,
136+ } ,
132137 asyncFriends : {
133138 type : new GraphQLList ( friendType ) ,
134139 async * resolve ( ) {
135140 yield await Promise . resolve ( friends [ 0 ] ) ;
136141 } ,
137142 } ,
143+ asyncEmptyFriends : {
144+ type : new GraphQLList ( friendType ) ,
145+ // eslint-disable-next-line require-yield
146+ async * resolve ( ) {
147+ await resolveOnNextTick ( ) ;
148+ } ,
149+ } ,
138150 nestedObject : { type : nestedObject , resolve : ( ) => ( { } ) } ,
151+ promiseNestedObject : {
152+ type : nestedObject ,
153+ resolve : ( ) => Promise . resolve ( { } ) ,
154+ } ,
155+ nullNestedObject : { type : nestedObject , resolve : ( ) => null } ,
139156 anotherNestedObject : { type : anotherNestedObject , resolve : ( ) => ( { } ) } ,
140157 } ,
141158 name : 'Hero' ,
@@ -395,26 +412,14 @@ describe('Execute: defer directive', () => {
395412 }
396413 ` ) ;
397414 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' ,
405420 } ,
406- hasNext : true ,
407421 } ,
408- {
409- incremental : [
410- {
411- data : { } ,
412- path : [ 'hero' ] ,
413- } ,
414- ] ,
415- hasNext : false ,
416- } ,
417- ] ) ;
422+ } ) ;
418423 } ) ;
419424 it ( 'Can defer a fragment that is also not deferred, non-deferred fragment is first' , async ( ) => {
420425 const document = parse ( `
@@ -430,26 +435,14 @@ describe('Execute: defer directive', () => {
430435 }
431436 ` ) ;
432437 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' ,
440443 } ,
441- hasNext : true ,
442- } ,
443- {
444- incremental : [
445- {
446- data : { } ,
447- path : [ 'hero' ] ,
448- } ,
449- ] ,
450- hasNext : false ,
451444 } ,
452- ] ) ;
445+ } ) ;
453446 } ) ;
454447
455448 it ( 'Can defer an inline fragment' , async ( ) => {
@@ -578,9 +571,6 @@ describe('Execute: defer directive', () => {
578571 bar : 'bar' ,
579572 } ,
580573 } ,
581- anotherNestedObject : {
582- deeperObject : { } ,
583- } ,
584574 } ,
585575 path : [ 'hero' ] ,
586576 } ,
@@ -772,14 +762,6 @@ describe('Execute: defer directive', () => {
772762 } ,
773763 path : [ 'hero' , 'nestedObject' , 'deeperObject' ] ,
774764 } ,
775- {
776- data : {
777- nestedObject : {
778- deeperObject : { } ,
779- } ,
780- } ,
781- path : [ 'hero' ] ,
782- } ,
783765 ] ,
784766 hasNext : false ,
785767 } ,
@@ -860,6 +842,176 @@ describe('Execute: defer directive', () => {
860842 ] ) ;
861843 } ) ;
862844
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+
8631015 it ( 'Handles errors thrown in deferred fragments' , async ( ) => {
8641016 const document = parse ( `
8651017 query HeroNameQuery {
0 commit comments