@@ -15,6 +15,7 @@ import {
15
15
import { getFragmentDependenciesForAST } from 'graphql-language-service' ;
16
16
import { ReactNode , useCallback , useMemo , useRef , useState } from 'react' ;
17
17
import setValue from 'set-value' ;
18
+ import getValue from 'get-value' ;
18
19
19
20
import { useAutoCompleteLeafs , useEditorContext } from './editor' ;
20
21
import { UseAutoCompleteLeafsArgs } from './editor/hooks' ;
@@ -343,31 +344,85 @@ type IncrementalResult = {
343
344
incremental ?: ReadonlyArray < IncrementalResult > ;
344
345
label ?: string ;
345
346
items ?: ReadonlyArray < Record < string , unknown > > | null ;
347
+ pending ?: ReadonlyArray < { id : string ; path : ReadonlyArray < string | number > } > ;
348
+ completed ?: ReadonlyArray < {
349
+ id : string ;
350
+ errors ?: ReadonlyArray < GraphQLError > ;
351
+ } > ;
352
+ id ?: string ;
353
+ subPath ?: ReadonlyArray < string | number > ;
346
354
} ;
347
355
356
+ const pathsMap = new WeakMap <
357
+ ExecutionResult ,
358
+ Map < string , ReadonlyArray < string | number > >
359
+ > ( ) ;
360
+
348
361
/**
349
362
* @param executionResult The complete execution result object which will be
350
363
* mutated by merging the contents of the incremental result.
351
364
* @param incrementalResult The incremental result that will be merged into the
352
365
* complete execution result.
353
366
*/
354
- function mergeIncrementalResult (
355
- executionResult : ExecutionResult ,
367
+ export function mergeIncrementalResult (
368
+ executionResult : IncrementalResult ,
356
369
incrementalResult : IncrementalResult ,
357
370
) : void {
358
- const path = [ 'data' , ...( incrementalResult . path ?? [ ] ) ] ;
359
-
360
- if ( incrementalResult . items ) {
361
- for ( const item of incrementalResult . items ) {
362
- setValue ( executionResult , path . join ( '.' ) , item ) ;
363
- // Increment the last path segment (the array index) to merge the next item at the next index
364
- // eslint-disable-next-line unicorn/prefer-at -- cannot mutate the array using Array.at()
365
- ( path [ path . length - 1 ] as number ) ++ ;
371
+ let path : ReadonlyArray < string | number > | undefined = [
372
+ 'data' ,
373
+ ...( incrementalResult . path ?? [ ] ) ,
374
+ ] ;
375
+
376
+ for ( const result of [ executionResult , incrementalResult ] ) {
377
+ if ( result . pending ) {
378
+ let paths = pathsMap . get ( executionResult ) ;
379
+ if ( paths === undefined ) {
380
+ paths = new Map ( ) ;
381
+ pathsMap . set ( executionResult , paths ) ;
382
+ }
383
+
384
+ for ( const { id, path : pendingPath } of result . pending ) {
385
+ paths . set ( id , [ 'data' , ...pendingPath ] ) ;
386
+ }
366
387
}
367
388
}
368
389
369
- if ( incrementalResult . data ) {
370
- setValue ( executionResult , path . join ( '.' ) , incrementalResult . data , {
390
+ const { items } = incrementalResult ;
391
+ if ( items ) {
392
+ const { id } = incrementalResult ;
393
+ if ( id ) {
394
+ path = pathsMap . get ( executionResult ) ?. get ( id ) ;
395
+ if ( path === undefined ) {
396
+ throw new Error ( 'Invalid incremental delivery format.' ) ;
397
+ }
398
+
399
+ const list = getValue ( executionResult , path . join ( '.' ) ) ;
400
+ list . push ( ...items ) ;
401
+ } else {
402
+ path = [ 'data' , ...( incrementalResult . path ?? [ ] ) ] ;
403
+ for ( const item of items ) {
404
+ setValue ( executionResult , path . join ( '.' ) , item ) ;
405
+ // Increment the last path segment (the array index) to merge the next item at the next index
406
+ // eslint-disable-next-line unicorn/prefer-at -- cannot mutate the array using Array.at()
407
+ ( path [ path . length - 1 ] as number ) ++ ;
408
+ }
409
+ }
410
+ }
411
+
412
+ const { data } = incrementalResult ;
413
+ if ( data ) {
414
+ const { id } = incrementalResult ;
415
+ if ( id ) {
416
+ path = pathsMap . get ( executionResult ) ?. get ( id ) ;
417
+ if ( path === undefined ) {
418
+ throw new Error ( 'Invalid incremental delivery format.' ) ;
419
+ }
420
+ const { subPath } = incrementalResult ;
421
+ if ( subPath !== undefined ) {
422
+ path = [ ...path , ...subPath ] ;
423
+ }
424
+ }
425
+ setValue ( executionResult , path . join ( '.' ) , data , {
371
426
merge : true ,
372
427
} ) ;
373
428
}
@@ -390,4 +445,16 @@ function mergeIncrementalResult(
390
445
mergeIncrementalResult ( executionResult , incrementalSubResult ) ;
391
446
}
392
447
}
448
+
449
+ if ( incrementalResult . completed ) {
450
+ // Remove tracking and add additional errors
451
+ for ( const { id, errors } of incrementalResult . completed ) {
452
+ pathsMap . get ( executionResult ) ?. delete ( id ) ;
453
+
454
+ if ( errors ) {
455
+ executionResult . errors ||= [ ] ;
456
+ ( executionResult . errors as GraphQLError [ ] ) . push ( ...errors ) ;
457
+ }
458
+ }
459
+ }
393
460
}
0 commit comments