@@ -93,12 +93,15 @@ export interface FormattedSubsequentIncrementalExecutionResult<
93
93
extensions ?: TExtensions ;
94
94
}
95
95
96
+ interface RawDeferResult < TData = ObjMap < unknown > > {
97
+ errors ?: ReadonlyArray < GraphQLError > ;
98
+ data : TData ;
99
+ }
100
+
96
101
export interface IncrementalDeferResult <
97
102
TData = ObjMap < unknown > ,
98
103
TExtensions = ObjMap < unknown > ,
99
- > {
100
- errors ?: ReadonlyArray < GraphQLError > ;
101
- data : TData ;
104
+ > extends RawDeferResult < TData > {
102
105
id : string ;
103
106
subPath ?: ReadonlyArray < string | number > ;
104
107
extensions ?: TExtensions ;
@@ -115,12 +118,15 @@ export interface FormattedIncrementalDeferResult<
115
118
extensions ?: TExtensions ;
116
119
}
117
120
118
- export interface IncrementalStreamResult <
119
- TData = Array < unknown > ,
120
- TExtensions = ObjMap < unknown > ,
121
- > {
121
+ interface RawStreamItemsResult < TData = ReadonlyArray < unknown > > {
122
122
errors ?: ReadonlyArray < GraphQLError > ;
123
123
items : TData ;
124
+ }
125
+
126
+ export interface IncrementalStreamResult <
127
+ TData = ReadonlyArray < unknown > ,
128
+ TExtensions = ObjMap < unknown > ,
129
+ > extends RawStreamItemsResult < TData > {
124
130
id : string ;
125
131
subPath ?: ReadonlyArray < string | number > ;
126
132
extensions ?: TExtensions ;
@@ -166,23 +172,27 @@ export interface FormattedCompletedResult {
166
172
}
167
173
168
174
export function buildIncrementalResponse (
175
+ context : IncrementalPublisherContext ,
169
176
result : ObjMap < unknown > ,
170
- errors : ReadonlyArray < GraphQLError > ,
177
+ errors : ReadonlyArray < GraphQLError > | undefined ,
171
178
futures : ReadonlyArray < Future > ,
172
- cancellableStreams : Set < StreamRecord > ,
173
179
) : ExperimentalIncrementalExecutionResults {
174
- const incrementalPublisher = new IncrementalPublisher ( cancellableStreams ) ;
180
+ const incrementalPublisher = new IncrementalPublisher ( context ) ;
175
181
return incrementalPublisher . buildResponse ( result , errors , futures ) ;
176
182
}
177
183
184
+ interface IncrementalPublisherContext {
185
+ cancellableStreams ?: Set < StreamRecord > | undefined ;
186
+ }
187
+
178
188
/**
179
189
* This class is used to publish incremental results to the client, enabling semi-concurrent
180
190
* execution while preserving result order.
181
191
*
182
192
* @internal
183
193
*/
184
194
class IncrementalPublisher {
185
- private _cancellableStreams : Set < StreamRecord > ;
195
+ private _context : IncrementalPublisherContext ;
186
196
private _nextId : number ;
187
197
private _pending : Set < SubsequentResultRecord > ;
188
198
private _completedResultQueue : Array < FutureResult > ;
@@ -193,8 +203,8 @@ class IncrementalPublisher {
193
203
private _signalled ! : Promise < unknown > ;
194
204
private _resolve ! : ( ) => void ;
195
205
196
- constructor ( cancellableStreams : Set < StreamRecord > ) {
197
- this . _cancellableStreams = cancellableStreams ;
206
+ constructor ( context : IncrementalPublisherContext ) {
207
+ this . _context = context ;
198
208
this . _nextId = 0 ;
199
209
this . _pending = new Set ( ) ;
200
210
this . _completedResultQueue = [ ] ;
@@ -206,7 +216,7 @@ class IncrementalPublisher {
206
216
207
217
buildResponse (
208
218
data : ObjMap < unknown > ,
209
- errors : ReadonlyArray < GraphQLError > ,
219
+ errors : ReadonlyArray < GraphQLError > | undefined ,
210
220
futures : ReadonlyArray < Future > ,
211
221
) : ExperimentalIncrementalExecutionResults {
212
222
this . _addFutures ( futures ) ;
@@ -215,7 +225,7 @@ class IncrementalPublisher {
215
225
const pending = this . _pendingSourcesToResults ( ) ;
216
226
217
227
const initialResult : InitialIncrementalExecutionResult =
218
- errors . length === 0
228
+ errors === undefined
219
229
? { data, pending, hasNext : true }
220
230
: { errors, data, pending, hasNext : true } ;
221
231
@@ -425,8 +435,12 @@ class IncrementalPublisher {
425
435
} ;
426
436
427
437
const returnStreamIterators = async ( ) : Promise < void > => {
438
+ const cancellableStreams = this . _context . cancellableStreams ;
439
+ if ( cancellableStreams === undefined ) {
440
+ return ;
441
+ }
428
442
const promises : Array < Promise < unknown > > = [ ] ;
429
- for ( const streamRecord of this . _cancellableStreams ) {
443
+ for ( const streamRecord of cancellableStreams ) {
430
444
if ( streamRecord . earlyReturn !== undefined ) {
431
445
promises . push ( streamRecord . earlyReturn ( ) ) ;
432
446
}
@@ -475,27 +489,36 @@ class IncrementalPublisher {
475
489
}
476
490
477
491
private _handleCompletedDeferredGroupedFieldSet (
478
- result : DeferredGroupedFieldSetResult ,
492
+ deferredGroupedFieldSetResult : DeferredGroupedFieldSetResult ,
479
493
) : void {
480
- if ( ! isReconcilableDeferredGroupedFieldSetResult ( result ) ) {
481
- for ( const deferredFragmentRecord of result . deferredFragmentRecords ) {
494
+ if (
495
+ isNonReconcilableDeferredGroupedFieldSetResult (
496
+ deferredGroupedFieldSetResult ,
497
+ )
498
+ ) {
499
+ for ( const deferredFragmentRecord of deferredGroupedFieldSetResult . deferredFragmentRecords ) {
482
500
const id = deferredFragmentRecord . id ;
483
501
if ( id !== undefined ) {
484
- this . _completed . push ( { id, errors : result . errors } ) ;
502
+ this . _completed . push ( {
503
+ id,
504
+ errors : deferredGroupedFieldSetResult . errors ,
505
+ } ) ;
485
506
this . _pending . delete ( deferredFragmentRecord ) ;
486
507
}
487
508
}
488
509
return ;
489
510
}
490
- for ( const deferredFragmentRecord of result . deferredFragmentRecords ) {
491
- deferredFragmentRecord . reconcilableResults . push ( result ) ;
511
+ for ( const deferredFragmentRecord of deferredGroupedFieldSetResult . deferredFragmentRecords ) {
512
+ deferredFragmentRecord . reconcilableResults . push (
513
+ deferredGroupedFieldSetResult ,
514
+ ) ;
492
515
}
493
516
494
- if ( result . futures ) {
495
- this . _addFutures ( result . futures ) ;
517
+ if ( deferredGroupedFieldSetResult . futures ) {
518
+ this . _addFutures ( deferredGroupedFieldSetResult . futures ) ;
496
519
}
497
520
498
- for ( const deferredFragmentRecord of result . deferredFragmentRecords ) {
521
+ for ( const deferredFragmentRecord of deferredGroupedFieldSetResult . deferredFragmentRecords ) {
499
522
const id = deferredFragmentRecord . id ;
500
523
// TODO: add test case for this.
501
524
// Presumably, this can occur if an error causes a fragment to be completed early,
@@ -522,12 +545,9 @@ class IncrementalPublisher {
522
545
fragmentResult ,
523
546
) ;
524
547
const incrementalEntry : IncrementalDeferResult = {
525
- data : fragmentResult . data ,
548
+ ... fragmentResult . result ,
526
549
id : bestId ,
527
550
} ;
528
- if ( result . errors . length > 0 ) {
529
- incrementalEntry . errors = fragmentResult . errors ;
530
- }
531
551
if ( subPath !== undefined ) {
532
552
incrementalEntry . subPath = subPath ;
533
553
}
@@ -548,44 +568,48 @@ class IncrementalPublisher {
548
568
this . _pruneEmpty ( ) ;
549
569
}
550
570
551
- private _handleCompletedStreamItems ( result : StreamItemsResult ) : void {
552
- const streamRecord = result . streamRecord ;
571
+ private _handleCompletedStreamItems (
572
+ streamItemsResult : StreamItemsResult ,
573
+ ) : void {
574
+ const streamRecord = streamItemsResult . streamRecord ;
553
575
const id = streamRecord . id ;
554
576
// TODO: Consider adding invariant or non-null assertion, as this should never happen. Since the stream is converted into a linked list
555
577
// for ordering purposes, if an entry errors, additional entries will not be processed.
556
578
/* c8 ignore next 3 */
557
579
if ( id === undefined ) {
558
580
return ;
559
581
}
560
- if ( result . items === undefined ) {
582
+ if ( streamItemsResult . result === undefined ) {
561
583
this . _completed . push ( { id } ) ;
562
584
this . _pending . delete ( streamRecord ) ;
563
- this . _cancellableStreams . delete ( streamRecord ) ;
564
- } else if ( result . items === null ) {
585
+ const cancellableStreams = this . _context . cancellableStreams ;
586
+ if ( cancellableStreams !== undefined ) {
587
+ cancellableStreams . delete ( streamRecord ) ;
588
+ }
589
+ } else if ( streamItemsResult . result === null ) {
565
590
this . _completed . push ( {
566
591
id,
567
- errors : result . errors ,
592
+ errors : streamItemsResult . errors ,
568
593
} ) ;
569
594
this . _pending . delete ( streamRecord ) ;
570
- this . _cancellableStreams . delete ( streamRecord ) ;
595
+ const cancellableStreams = this . _context . cancellableStreams ;
596
+ if ( cancellableStreams !== undefined ) {
597
+ cancellableStreams . delete ( streamRecord ) ;
598
+ }
571
599
streamRecord . earlyReturn ?.( ) . catch ( ( ) => {
572
600
/* c8 ignore next 1 */
573
601
// ignore error
574
602
} ) ;
575
603
} else {
576
604
const incrementalEntry : IncrementalStreamResult = {
577
605
id,
578
- items : result . items as Array < unknown > , // FIX!
606
+ ... streamItemsResult . result ,
579
607
} ;
580
608
581
- if ( result . errors !== undefined && result . errors . length > 0 ) {
582
- incrementalEntry . errors = result . errors ;
583
- }
584
-
585
609
this . _incremental . push ( incrementalEntry ) ;
586
610
587
- if ( result . futures ) {
588
- this . _addFutures ( result . futures ) ;
611
+ if ( streamItemsResult . futures ) {
612
+ this . _addFutures ( streamItemsResult . futures ) ;
589
613
this . _pruneEmpty ( ) ;
590
614
}
591
615
}
@@ -639,35 +663,39 @@ export function isDeferredGroupedFieldSetRecord(
639
663
export interface IncrementalContext {
640
664
deferUsageSet : DeferUsageSet | undefined ;
641
665
path : Path | undefined ;
642
- errors : Array < GraphQLError > ;
643
- errorPaths : Set < Path > ;
644
- futures : Array < Future > ;
666
+ errors ?: Map < Path | undefined , GraphQLError > | undefined ;
667
+ futures ?: Array < Future > | undefined ;
645
668
}
646
669
647
- export interface DeferredGroupedFieldSetResult {
648
- deferredFragmentRecords : ReadonlyArray < DeferredFragmentRecord > ;
649
- path : Array < string | number > ;
650
- data : ObjMap < unknown > | null ;
651
- futures ?: ReadonlyArray < Future > ;
652
- errors : ReadonlyArray < GraphQLError > ;
653
- }
670
+ export type DeferredGroupedFieldSetResult =
671
+ | ReconcilableDeferredGroupedFieldSetResult
672
+ | NonReconcilableDeferredGroupedFieldSetResult ;
654
673
655
674
export function isDeferredGroupedFieldSetResult (
656
675
subsequentResult : DeferredGroupedFieldSetResult | StreamItemsResult ,
657
676
) : subsequentResult is DeferredGroupedFieldSetResult {
658
677
return 'deferredFragmentRecords' in subsequentResult ;
659
678
}
660
679
661
- interface ReconcilableDeferredGroupedFieldSetResult
662
- extends DeferredGroupedFieldSetResult {
663
- data : ObjMap < unknown > ;
680
+ interface ReconcilableDeferredGroupedFieldSetResult {
681
+ deferredFragmentRecords : ReadonlyArray < DeferredFragmentRecord > ;
682
+ path : Array < string | number > ;
683
+ result : RawDeferResult ;
684
+ futures ?: ReadonlyArray < Future > | undefined ;
664
685
sent ?: true | undefined ;
665
686
}
666
687
667
- export function isReconcilableDeferredGroupedFieldSetResult (
688
+ interface NonReconcilableDeferredGroupedFieldSetResult {
689
+ result : null ;
690
+ errors : ReadonlyArray < GraphQLError > ;
691
+ deferredFragmentRecords : ReadonlyArray < DeferredFragmentRecord > ;
692
+ path : Array < string | number > ;
693
+ }
694
+
695
+ export function isNonReconcilableDeferredGroupedFieldSetResult (
668
696
deferredGroupedFieldSetResult : DeferredGroupedFieldSetResult ,
669
- ) : deferredGroupedFieldSetResult is ReconcilableDeferredGroupedFieldSetResult {
670
- return deferredGroupedFieldSetResult . data ! == null ;
697
+ ) : deferredGroupedFieldSetResult is NonReconcilableDeferredGroupedFieldSetResult {
698
+ return deferredGroupedFieldSetResult . result = == null ;
671
699
}
672
700
673
701
/** @internal */
@@ -691,9 +719,6 @@ export class DeferredGroupedFieldSetRecord {
691
719
const incrementalContext : IncrementalContext = {
692
720
deferUsageSet,
693
721
path,
694
- errors : [ ] ,
695
- errorPaths : new Set ( ) ,
696
- futures : [ ] ,
697
722
} ;
698
723
699
724
for ( const deferredFragmentRecord of deferredFragmentRecords ) {
@@ -752,24 +777,36 @@ export class StreamRecord {
752
777
}
753
778
}
754
779
755
- interface NonTerminatingStreamItemsResult {
780
+ interface NonReconcilableStreamItemsResult {
756
781
streamRecord : StreamRecord ;
757
- items : ReadonlyArray < unknown > | null ;
758
- futures ?: ReadonlyArray < Future > ;
782
+ result : null ;
759
783
errors : ReadonlyArray < GraphQLError > ;
760
784
}
761
785
786
+ interface NonTerminatingStreamItemsResult {
787
+ streamRecord : StreamRecord ;
788
+ result : RawStreamItemsResult ;
789
+ futures ?: ReadonlyArray < Future > | undefined ;
790
+ }
791
+
762
792
interface TerminatingStreamItemsResult {
763
793
streamRecord : StreamRecord ;
764
- items ?: never ;
794
+ result ?: never ;
765
795
futures ?: never ;
766
796
errors ?: never ;
767
797
}
768
798
769
799
export type StreamItemsResult =
800
+ | NonReconcilableStreamItemsResult
770
801
| NonTerminatingStreamItemsResult
771
802
| TerminatingStreamItemsResult ;
772
803
804
+ export function isNonTerminatingStreamItemsResult (
805
+ streamItemsResult : StreamItemsResult ,
806
+ ) : streamItemsResult is NonTerminatingStreamItemsResult {
807
+ return streamItemsResult . result != null ;
808
+ }
809
+
773
810
/** @internal */
774
811
export class StreamItemsRecord {
775
812
streamRecord : StreamRecord ;
@@ -789,9 +826,6 @@ export class StreamItemsRecord {
789
826
const incrementalContext : IncrementalContext = {
790
827
deferUsageSet : undefined ,
791
828
path : itemPath ,
792
- errors : [ ] ,
793
- errorPaths : new Set ( ) ,
794
- futures : [ ] ,
795
829
} ;
796
830
797
831
this . _result = executor ( incrementalContext ) ;
@@ -810,12 +844,13 @@ export class StreamItemsRecord {
810
844
private _prependNextStreamItems (
811
845
result : StreamItemsResult ,
812
846
) : StreamItemsResult {
813
- return this . nextStreamItems === undefined
814
- ? result
815
- : {
847
+ return isNonTerminatingStreamItemsResult ( result ) &&
848
+ this . nextStreamItems !== undefined
849
+ ? {
816
850
...result ,
817
851
futures : [ this . nextStreamItems , ...( result . futures ?? [ ] ) ] ,
818
- } ;
852
+ }
853
+ : result ;
819
854
}
820
855
}
821
856
0 commit comments