@@ -40,6 +40,23 @@ const friends = [
40
40
{ name : 'C-3PO' , id : 4 } ,
41
41
] ;
42
42
43
+ const deeperObject = new GraphQLObjectType ( {
44
+ fields : {
45
+ foo : { type : GraphQLString , resolve : ( ) => 'foo' } ,
46
+ bar : { type : GraphQLString , resolve : ( ) => 'bar' } ,
47
+ baz : { type : GraphQLString , resolve : ( ) => 'baz' } ,
48
+ bak : { type : GraphQLString , resolve : ( ) => 'bak' } ,
49
+ } ,
50
+ name : 'DeeperObject' ,
51
+ } ) ;
52
+
53
+ const nestedObject = new GraphQLObjectType ( {
54
+ fields : {
55
+ deeperObject : { type : deeperObject , resolve : ( ) => ( { } ) } ,
56
+ } ,
57
+ name : 'NestedObject' ,
58
+ } ) ;
59
+
43
60
const heroType = new GraphQLObjectType ( {
44
61
fields : {
45
62
id : { type : GraphQLID } ,
@@ -75,6 +92,7 @@ const heroType = new GraphQLObjectType({
75
92
yield await Promise . resolve ( friends [ 0 ] ) ;
76
93
} ,
77
94
} ,
95
+ nestedObject : { type : nestedObject , resolve : ( ) => ( { } ) } ,
78
96
} ,
79
97
name : 'Hero' ,
80
98
} ) ;
@@ -141,7 +159,6 @@ describe('Execute: defer directive', () => {
141
159
incremental : [
142
160
{
143
161
data : {
144
- id : '1' ,
145
162
name : 'Luke' ,
146
163
} ,
147
164
path : [ 'hero' ] ,
@@ -307,15 +324,10 @@ describe('Execute: defer directive', () => {
307
324
} ,
308
325
{
309
326
incremental : [
310
- {
311
- data : {
312
- friends : [ { name : 'Han' } , { name : 'Leia' } , { name : 'C-3PO' } ] ,
313
- } ,
314
- path : [ 'hero' ] ,
315
- } ,
316
327
{
317
328
data : {
318
329
name : 'Luke' ,
330
+ friends : [ { name : 'Han' } , { name : 'Leia' } , { name : 'C-3PO' } ] ,
319
331
} ,
320
332
path : [ 'hero' ] ,
321
333
} ,
@@ -351,9 +363,7 @@ describe('Execute: defer directive', () => {
351
363
{
352
364
incremental : [
353
365
{
354
- data : {
355
- name : 'Luke' ,
356
- } ,
366
+ data : { } ,
357
367
path : [ 'hero' ] ,
358
368
} ,
359
369
] ,
@@ -388,9 +398,7 @@ describe('Execute: defer directive', () => {
388
398
{
389
399
incremental : [
390
400
{
391
- data : {
392
- name : 'Luke' ,
393
- } ,
401
+ data : { } ,
394
402
path : [ 'hero' ] ,
395
403
} ,
396
404
] ,
@@ -423,6 +431,188 @@ describe('Execute: defer directive', () => {
423
431
} ,
424
432
] ) ;
425
433
} ) ;
434
+
435
+ it ( 'Can deduplicate multiple defers on the same object' , async ( ) => {
436
+ const document = parse ( `
437
+ query {
438
+ hero {
439
+ friends {
440
+ ... @defer {
441
+ ...FriendFrag
442
+ ... @defer {
443
+ ...FriendFrag
444
+ ... @defer {
445
+ ...FriendFrag
446
+ ... @defer {
447
+ ...FriendFrag
448
+ }
449
+ }
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ fragment FriendFrag on Friend {
457
+ id
458
+ name
459
+ }
460
+ ` ) ;
461
+ const result = await complete ( document ) ;
462
+
463
+ expectJSON ( result ) . toDeepEqual ( [
464
+ {
465
+ data : { hero : { friends : [ { } , { } , { } ] } } ,
466
+ hasNext : true ,
467
+ } ,
468
+ {
469
+ incremental : [
470
+ { data : { id : '2' , name : 'Han' } , path : [ 'hero' , 'friends' , 0 ] } ,
471
+ { data : { id : '3' , name : 'Leia' } , path : [ 'hero' , 'friends' , 1 ] } ,
472
+ { data : { id : '4' , name : 'C-3PO' } , path : [ 'hero' , 'friends' , 2 ] } ,
473
+ ] ,
474
+ hasNext : false ,
475
+ } ,
476
+ ] ) ;
477
+ } ) ;
478
+
479
+ it ( 'Can deduplicate fields with deferred fragments at multiple levels' , async ( ) => {
480
+ const document = parse ( `
481
+ query {
482
+ hero {
483
+ nestedObject {
484
+ deeperObject {
485
+ foo
486
+ }
487
+ }
488
+ ... @defer {
489
+ nestedObject {
490
+ deeperObject {
491
+ foo
492
+ bar
493
+ }
494
+ ... @defer {
495
+ deeperObject {
496
+ foo
497
+ bar
498
+ baz
499
+ ... @defer {
500
+ foo
501
+ bar
502
+ baz
503
+ bak
504
+ }
505
+ }
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
+ ` ) ;
512
+ const result = await complete ( document ) ;
513
+ expectJSON ( result ) . toDeepEqual ( [
514
+ {
515
+ data : {
516
+ hero : {
517
+ nestedObject : {
518
+ deeperObject : {
519
+ foo : 'foo' ,
520
+ } ,
521
+ } ,
522
+ } ,
523
+ } ,
524
+ hasNext : true ,
525
+ } ,
526
+ {
527
+ incremental : [
528
+ {
529
+ data : {
530
+ bak : 'bak' ,
531
+ } ,
532
+ path : [ 'hero' , 'nestedObject' , 'deeperObject' ] ,
533
+ } ,
534
+ {
535
+ data : {
536
+ deeperObject : {
537
+ baz : 'baz' ,
538
+ } ,
539
+ } ,
540
+ path : [ 'hero' , 'nestedObject' ] ,
541
+ } ,
542
+ {
543
+ data : {
544
+ nestedObject : {
545
+ deeperObject : {
546
+ bar : 'bar' ,
547
+ } ,
548
+ } ,
549
+ } ,
550
+ path : [ 'hero' ] ,
551
+ } ,
552
+ ] ,
553
+ hasNext : false ,
554
+ } ,
555
+ ] ) ;
556
+ } ) ;
557
+
558
+ it ( 'Can deduplicate fields with deferred fragments at the same level in different branches' , async ( ) => {
559
+ const document = parse ( `
560
+ query {
561
+ hero {
562
+ nestedObject {
563
+ deeperObject {
564
+ ... @defer {
565
+ foo
566
+ }
567
+ }
568
+ }
569
+ ... @defer {
570
+ nestedObject {
571
+ deeperObject {
572
+ ... @defer {
573
+ bar
574
+ }
575
+ }
576
+ }
577
+ }
578
+ }
579
+ }
580
+ ` ) ;
581
+ const result = await complete ( document ) ;
582
+ expectJSON ( result ) . toDeepEqual ( [
583
+ {
584
+ data : {
585
+ hero : {
586
+ nestedObject : {
587
+ deeperObject : { } ,
588
+ } ,
589
+ } ,
590
+ } ,
591
+ hasNext : true ,
592
+ } ,
593
+ {
594
+ incremental : [
595
+ {
596
+ data : {
597
+ foo : 'foo' ,
598
+ bar : 'bar' ,
599
+ } ,
600
+ path : [ 'hero' , 'nestedObject' , 'deeperObject' ] ,
601
+ } ,
602
+ {
603
+ data : {
604
+ nestedObject : {
605
+ deeperObject : { } ,
606
+ } ,
607
+ } ,
608
+ path : [ 'hero' ] ,
609
+ } ,
610
+ ] ,
611
+ hasNext : false ,
612
+ } ,
613
+ ] ) ;
614
+ } ) ;
615
+
426
616
it ( 'Handles errors thrown in deferred fragments' , async ( ) => {
427
617
const document = parse ( `
428
618
query HeroNameQuery {
0 commit comments