@@ -9,24 +9,49 @@ import type {
99 ReconcilableDeferredGroupedFieldSetResult ,
1010 SubsequentResultRecord ,
1111} from './types.js' ;
12- import {
13- isDeferredFragmentRecord ,
14- isDeferredGroupedFieldSetRecord ,
15- } from './types.js' ;
12+ import { isDeferredGroupedFieldSetRecord } from './types.js' ;
13+
14+ interface DeferredFragmentNode {
15+ deferredFragmentRecord : DeferredFragmentRecord ;
16+ expectedReconcilableResults : number ;
17+ results : Array < DeferredGroupedFieldSetResult > ;
18+ reconcilableResults : Array < ReconcilableDeferredGroupedFieldSetResult > ;
19+ children : Array < DeferredFragmentNode > ;
20+ }
21+
22+ function isDeferredFragmentNode (
23+ node : DeferredFragmentNode | undefined ,
24+ ) : node is DeferredFragmentNode {
25+ return node !== undefined ;
26+ }
27+
28+ function isStreamNode (
29+ subsequentResultNode : SubsequentResultNode ,
30+ ) : subsequentResultNode is SubsequentResultRecord {
31+ return 'path' in subsequentResultNode ;
32+ }
33+
34+ type SubsequentResultNode = DeferredFragmentNode | SubsequentResultRecord ;
1635
1736/**
1837 * @internal
1938 */
2039export class IncrementalGraph {
21- private _pending : Set < SubsequentResultRecord > ;
22- private _newPending : Set < SubsequentResultRecord > ;
40+ private _pending : Set < SubsequentResultNode > ;
41+ private _deferredFragmentNodes : Map <
42+ DeferredFragmentRecord ,
43+ DeferredFragmentNode
44+ > ;
45+
46+ private _newPending : Set < SubsequentResultNode > ;
2347 private _completedQueue : Array < IncrementalDataRecordResult > ;
2448 private _nextQueue : Array <
2549 ( iterable : IteratorResult < Iterable < IncrementalDataRecordResult > > ) => void
2650 > ;
2751
2852 constructor ( ) {
2953 this . _pending = new Set ( ) ;
54+ this . _deferredFragmentNodes = new Map ( ) ;
3055 this . _newPending = new Set ( ) ;
3156 this . _completedQueue = [ ] ;
3257 this . _nextQueue = [ ] ;
@@ -38,9 +63,10 @@ export class IncrementalGraph {
3863 for ( const incrementalDataRecord of incrementalDataRecords ) {
3964 if ( isDeferredGroupedFieldSetRecord ( incrementalDataRecord ) ) {
4065 for ( const deferredFragmentRecord of incrementalDataRecord . deferredFragmentRecords ) {
41- deferredFragmentRecord . expectedReconcilableResults ++ ;
42-
43- this . _addDeferredFragmentRecord ( deferredFragmentRecord ) ;
66+ const deferredFragmentNode = this . _addDeferredFragmentNode (
67+ deferredFragmentRecord ,
68+ ) ;
69+ deferredFragmentNode . expectedReconcilableResults ++ ;
4470 }
4571
4672 const result = incrementalDataRecord . result ;
@@ -73,21 +99,33 @@ export class IncrementalGraph {
7399 }
74100 }
75101
102+ addCompletedReconcilableDeferredGroupedFieldSet (
103+ reconcilableResult : ReconcilableDeferredGroupedFieldSetResult ,
104+ ) : void {
105+ const deferredFragmentNodes : Array < DeferredFragmentNode > =
106+ reconcilableResult . deferredFragmentRecords
107+ . map ( ( deferredFragmentRecord ) =>
108+ this . _deferredFragmentNodes . get ( deferredFragmentRecord ) ,
109+ )
110+ . filter < DeferredFragmentNode > ( isDeferredFragmentNode ) ;
111+ for ( const deferredFragmentNode of deferredFragmentNodes ) {
112+ deferredFragmentNode . reconcilableResults . push ( reconcilableResult ) ;
113+ }
114+ }
115+
76116 getNewPending ( ) : ReadonlyArray < SubsequentResultRecord > {
77- const newPending = [ ] ;
117+ const newPending : Array < SubsequentResultRecord > = [ ] ;
78118 for ( const node of this . _newPending ) {
79- if ( isDeferredFragmentRecord ( node ) ) {
80- if ( node . expectedReconcilableResults ) {
81- this . _pending . add ( node ) ;
82- newPending . push ( node ) ;
83- continue ;
84- }
119+ if ( isStreamNode ( node ) ) {
120+ this . _pending . add ( node ) ;
121+ newPending . push ( node ) ;
122+ } else if ( node . expectedReconcilableResults ) {
123+ this . _pending . add ( node ) ;
124+ newPending . push ( node . deferredFragmentRecord ) ;
125+ } else {
85126 for ( const child of node . children ) {
86127 this . _newPending . add ( child ) ;
87128 }
88- } else {
89- this . _pending . add ( node ) ;
90- newPending . push ( node ) ;
91129 }
92130 }
93131 this . _newPending . clear ( ) ;
@@ -134,15 +172,23 @@ export class IncrementalGraph {
134172 completeDeferredFragment (
135173 deferredFragmentRecord : DeferredFragmentRecord ,
136174 ) : Array < ReconcilableDeferredGroupedFieldSetResult > | undefined {
137- const reconcilableResults = deferredFragmentRecord . reconcilableResults ;
175+ const deferredFragmentNode = this . _deferredFragmentNodes . get (
176+ deferredFragmentRecord ,
177+ ) ;
178+ // TODO: add test case?
179+ /* c8 ignore next 3 */
180+ if ( deferredFragmentNode === undefined ) {
181+ return undefined ;
182+ }
183+ const reconcilableResults = deferredFragmentNode . reconcilableResults ;
138184 if (
139- deferredFragmentRecord . expectedReconcilableResults !==
185+ deferredFragmentNode . expectedReconcilableResults !==
140186 reconcilableResults . length
141187 ) {
142188 return ;
143189 }
144- this . removeSubsequentResultRecord ( deferredFragmentRecord ) ;
145- for ( const child of deferredFragmentRecord . children ) {
190+ this . _removePending ( deferredFragmentNode ) ;
191+ for ( const child of deferredFragmentNode . children ) {
146192 this . _newPending . add ( child ) ;
147193 for ( const result of child . results ) {
148194 this . _enqueue ( result ) ;
@@ -151,53 +197,86 @@ export class IncrementalGraph {
151197 return reconcilableResults ;
152198 }
153199
154- removeSubsequentResultRecord (
155- subsequentResultRecord : SubsequentResultRecord ,
156- ) : void {
157- this . _pending . delete ( subsequentResultRecord ) ;
200+ removeDeferredFragment ( deferredFragmentRecord : DeferredFragmentRecord ) : void {
201+ const deferredFragmentNode = this . _deferredFragmentNodes . get (
202+ deferredFragmentRecord ,
203+ ) ;
204+ // TODO: add test case?
205+ /* c8 ignore next 3 */
206+ if ( deferredFragmentNode === undefined ) {
207+ return ;
208+ }
209+ this . _removePending ( deferredFragmentNode ) ;
210+ this . _deferredFragmentNodes . delete ( deferredFragmentRecord ) ;
211+ // TODO: add test case for an erroring deferred fragment with child defers
212+ /* c8 ignore next 3 */
213+ for ( const child of deferredFragmentNode . children ) {
214+ this . removeDeferredFragment ( child . deferredFragmentRecord ) ;
215+ }
216+ }
217+
218+ removeStream ( streamRecord : SubsequentResultRecord ) : void {
219+ this . _removePending ( streamRecord ) ;
220+ }
221+
222+ private _removePending ( subsequentResultNode : SubsequentResultNode ) : void {
223+ this . _pending . delete ( subsequentResultNode ) ;
158224 if ( this . _pending . size === 0 ) {
159225 for ( const resolve of this . _nextQueue ) {
160226 resolve ( { value : undefined , done : true } ) ;
161227 }
162228 }
163229 }
164230
165- private _addDeferredFragmentRecord (
231+ private _addDeferredFragmentNode (
166232 deferredFragmentRecord : DeferredFragmentRecord ,
167- ) : void {
233+ ) : DeferredFragmentNode {
234+ let deferredFragmentNode = this . _deferredFragmentNodes . get (
235+ deferredFragmentRecord ,
236+ ) ;
237+ if ( deferredFragmentNode !== undefined ) {
238+ return deferredFragmentNode ;
239+ }
240+ deferredFragmentNode = {
241+ deferredFragmentRecord,
242+ expectedReconcilableResults : 0 ,
243+ results : [ ] ,
244+ reconcilableResults : [ ] ,
245+ children : [ ] ,
246+ } ;
247+ this . _deferredFragmentNodes . set (
248+ deferredFragmentRecord ,
249+ deferredFragmentNode ,
250+ ) ;
168251 const parent = deferredFragmentRecord . parent ;
169252 if ( parent === undefined ) {
170- // Below is equivalent and slightly faster version of:
171- // if (this._pending.has(deferredFragmentRecord)) { ... }
172- // as all released deferredFragmentRecords have ids.
173- if ( deferredFragmentRecord . id !== undefined ) {
174- return ;
175- }
176-
177- this . _newPending . add ( deferredFragmentRecord ) ;
178- return ;
253+ this . _newPending . add ( deferredFragmentNode ) ;
254+ return deferredFragmentNode ;
179255 }
180-
181- if ( parent . children . has ( deferredFragmentRecord ) ) {
182- return ;
183- }
184-
185- parent . children . add ( deferredFragmentRecord ) ;
186-
187- this . _addDeferredFragmentRecord ( parent ) ;
256+ const parentNode = this . _addDeferredFragmentNode ( parent ) ;
257+ parentNode . children . push ( deferredFragmentNode ) ;
258+ return deferredFragmentNode ;
188259 }
189260
190261 private _enqueueCompletedDeferredGroupedFieldSet (
191262 result : DeferredGroupedFieldSetResult ,
192263 ) : void {
193- let hasPendingParent = false ;
264+ let isPending = false ;
194265 for ( const deferredFragmentRecord of result . deferredFragmentRecords ) {
195- if ( deferredFragmentRecord . id !== undefined ) {
196- hasPendingParent = true ;
266+ const deferredFragmentNode = this . _deferredFragmentNodes . get (
267+ deferredFragmentRecord ,
268+ ) ;
269+ // TODO: add test case?
270+ /* c8 ignore next 3 */
271+ if ( deferredFragmentNode === undefined ) {
272+ continue ;
273+ }
274+ if ( this . _pending . has ( deferredFragmentNode ) ) {
275+ isPending = true ;
197276 }
198- deferredFragmentRecord . results . push ( result ) ;
277+ deferredFragmentNode . results . push ( result ) ;
199278 }
200- if ( hasPendingParent ) {
279+ if ( isPending ) {
201280 this . _enqueue ( result ) ;
202281 }
203282 }
0 commit comments