@@ -17,6 +17,7 @@ import type {
17
17
import type { StreamUsage } from './execute.js' ;
18
18
19
19
interface IncrementalUpdate < TData = unknown , TExtensions = ObjMap < unknown > > {
20
+ pending : ReadonlyArray < PendingResult > ;
20
21
incremental : ReadonlyArray < IncrementalResult < TData , TExtensions > > ;
21
22
completed : ReadonlyArray < CompletedResult > ;
22
23
}
@@ -65,6 +66,7 @@ export interface InitialIncrementalExecutionResult<
65
66
TExtensions = ObjMap < unknown > ,
66
67
> extends ExecutionResult < TData , TExtensions > {
67
68
data : TData ;
69
+ pending : ReadonlyArray < PendingResult > ;
68
70
hasNext : true ;
69
71
extensions ?: TExtensions ;
70
72
}
@@ -74,6 +76,7 @@ export interface FormattedInitialIncrementalExecutionResult<
74
76
TExtensions = ObjMap < unknown > ,
75
77
> extends FormattedExecutionResult < TData , TExtensions > {
76
78
data : TData ;
79
+ pending : ReadonlyArray < PendingResult > ;
77
80
hasNext : boolean ;
78
81
extensions ?: TExtensions ;
79
82
}
@@ -91,6 +94,7 @@ export interface FormattedSubsequentIncrementalExecutionResult<
91
94
TExtensions = ObjMap < unknown > ,
92
95
> {
93
96
hasNext : boolean ;
97
+ pending ?: ReadonlyArray < PendingResult > ;
94
98
incremental ?: ReadonlyArray < FormattedIncrementalResult < TData , TExtensions > > ;
95
99
completed ?: ReadonlyArray < FormattedCompletedResult > ;
96
100
extensions ?: TExtensions ;
@@ -147,6 +151,11 @@ export type FormattedIncrementalResult<
147
151
| FormattedIncrementalDeferResult < TData , TExtensions >
148
152
| FormattedIncrementalStreamResult < TData , TExtensions > ;
149
153
154
+ export interface PendingResult {
155
+ path : ReadonlyArray < string | number > ;
156
+ label ?: string ;
157
+ }
158
+
150
159
export interface CompletedResult {
151
160
path : ReadonlyArray < string | number > ;
152
161
label ?: string ;
@@ -373,10 +382,20 @@ export class IncrementalPublisher {
373
382
374
383
const errors = initialResultRecord . errors ;
375
384
const initialResult = errors . length === 0 ? { data } : { errors, data } ;
376
- if ( this . _pending . size > 0 ) {
385
+ const pending = this . _pending ;
386
+ if ( pending . size > 0 ) {
387
+ const pendingSources = new Set < DeferredFragmentRecord | StreamRecord > ( ) ;
388
+ for ( const subsequentResultRecord of pending ) {
389
+ const pendingSource = isStreamItemsRecord ( subsequentResultRecord )
390
+ ? subsequentResultRecord . streamRecord
391
+ : subsequentResultRecord ;
392
+ pendingSources . add ( pendingSource ) ;
393
+ }
394
+
377
395
return {
378
396
initialResult : {
379
397
...initialResult ,
398
+ pending : this . pendingSourcesToResults ( pendingSources ) ,
380
399
hasNext : true ,
381
400
} ,
382
401
subsequentResults : this . _subscribe ( ) ,
@@ -424,6 +443,23 @@ export class IncrementalPublisher {
424
443
} ) ;
425
444
}
426
445
446
+ pendingSourcesToResults (
447
+ pendingSources : ReadonlySet < DeferredFragmentRecord | StreamRecord > ,
448
+ ) : Array < PendingResult > {
449
+ const pendingResults : Array < PendingResult > = [ ] ;
450
+ for ( const pendingSource of pendingSources ) {
451
+ pendingSource . pendingSent = true ;
452
+ const pendingResult : PendingResult = {
453
+ path : pendingSource . path ,
454
+ } ;
455
+ if ( pendingSource . label !== undefined ) {
456
+ pendingResult . label = pendingSource . label ;
457
+ }
458
+ pendingResults . push ( pendingResult ) ;
459
+ }
460
+ return pendingResults ;
461
+ }
462
+
427
463
private _subscribe ( ) : AsyncGenerator <
428
464
SubsequentIncrementalExecutionResult ,
429
465
void ,
@@ -538,14 +574,18 @@ export class IncrementalPublisher {
538
574
private _getIncrementalResult (
539
575
completedRecords : ReadonlySet < SubsequentResultRecord > ,
540
576
) : SubsequentIncrementalExecutionResult | undefined {
541
- const { incremental, completed } = this . _processPending ( completedRecords ) ;
577
+ const { pending, incremental, completed } =
578
+ this . _processPending ( completedRecords ) ;
542
579
543
580
const hasNext = this . _pending . size > 0 ;
544
581
if ( incremental . length === 0 && completed . length === 0 && hasNext ) {
545
582
return undefined ;
546
583
}
547
584
548
585
const result : SubsequentIncrementalExecutionResult = { hasNext } ;
586
+ if ( pending . length ) {
587
+ result . pending = pending ;
588
+ }
549
589
if ( incremental . length ) {
550
590
result . incremental = incremental ;
551
591
}
@@ -559,19 +599,27 @@ export class IncrementalPublisher {
559
599
private _processPending (
560
600
completedRecords : ReadonlySet < SubsequentResultRecord > ,
561
601
) : IncrementalUpdate {
602
+ const newPendingSources = new Set < DeferredFragmentRecord | StreamRecord > ( ) ;
562
603
const incrementalResults : Array < IncrementalResult > = [ ] ;
563
604
const completedResults : Array < CompletedResult > = [ ] ;
564
605
for ( const subsequentResultRecord of completedRecords ) {
565
606
for ( const child of subsequentResultRecord . children ) {
566
607
if ( child . filtered ) {
567
608
continue ;
568
609
}
610
+ const pendingSource = isStreamItemsRecord ( child )
611
+ ? child . streamRecord
612
+ : child ;
613
+ if ( ! pendingSource . pendingSent ) {
614
+ newPendingSources . add ( pendingSource ) ;
615
+ }
569
616
this . _publish ( child ) ;
570
617
}
571
618
if ( isStreamItemsRecord ( subsequentResultRecord ) ) {
572
619
if ( ! subsequentResultRecord . sent ) {
573
620
subsequentResultRecord . sent = true ;
574
621
if ( subsequentResultRecord . isFinalRecord ) {
622
+ newPendingSources . delete ( subsequentResultRecord . streamRecord ) ;
575
623
completedResults . push (
576
624
this . _completedRecordToResult (
577
625
subsequentResultRecord . streamRecord ,
@@ -595,6 +643,7 @@ export class IncrementalPublisher {
595
643
incrementalResults . push ( incrementalResult ) ;
596
644
}
597
645
} else {
646
+ newPendingSources . delete ( subsequentResultRecord ) ;
598
647
completedResults . push (
599
648
this . _completedRecordToResult ( subsequentResultRecord ) ,
600
649
) ;
@@ -619,6 +668,7 @@ export class IncrementalPublisher {
619
668
}
620
669
621
670
return {
671
+ pending : this . pendingSourcesToResults ( newPendingSources ) ,
622
672
incremental : incrementalResults ,
623
673
completed : completedResults ,
624
674
} ;
@@ -777,6 +827,7 @@ export class DeferredFragmentRecord {
777
827
deferredGroupedFieldSetRecords : Set < DeferredGroupedFieldSetRecord > ;
778
828
errors : Array < GraphQLError > ;
779
829
filtered : boolean ;
830
+ pendingSent ?: boolean ;
780
831
_pending : Set < DeferredGroupedFieldSetRecord > ;
781
832
782
833
constructor ( opts : { path : Path | undefined ; label : string | undefined } ) {
@@ -796,6 +847,7 @@ export class StreamRecord {
796
847
path : ReadonlyArray < string | number > ;
797
848
errors : Array < GraphQLError > ;
798
849
asyncIterator ?: AsyncIterator < unknown > | undefined ;
850
+ pendingSent ?: boolean ;
799
851
constructor ( opts : {
800
852
label : string | undefined ;
801
853
path : Path ;
@@ -838,15 +890,15 @@ export type IncrementalDataRecord =
838
890
| DeferredGroupedFieldSetRecord
839
891
| StreamItemsRecord ;
840
892
841
- type SubsequentResultRecord = DeferredFragmentRecord | StreamItemsRecord ;
893
+ export type SubsequentResultRecord = DeferredFragmentRecord | StreamItemsRecord ;
842
894
843
895
function isDeferredGroupedFieldSetRecord (
844
896
incrementalDataRecord : unknown ,
845
897
) : incrementalDataRecord is DeferredGroupedFieldSetRecord {
846
898
return incrementalDataRecord instanceof DeferredGroupedFieldSetRecord ;
847
899
}
848
900
849
- function isStreamItemsRecord (
901
+ export function isStreamItemsRecord (
850
902
subsequentResultRecord : unknown ,
851
903
) : subsequentResultRecord is StreamItemsRecord {
852
904
return subsequentResultRecord instanceof StreamItemsRecord ;
0 commit comments