@@ -366,7 +366,7 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
366
366
{newPendingResults} as pending.
367
367
- For each completed child Future node of a root node in {graph}:
368
368
- Let {completedFuture} be that Future; let {result} be its result.
369
- - If {data} on { result} is {null }:
369
+ - If {FutureCompletedWithoutData(completedFuture, result) } is {true }:
370
370
- Initialize {completed} to an empty list.
371
371
- Let {parents} be the parents of {completedFuture}.
372
372
- Initialize {completed} to an empty list.
@@ -380,8 +380,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
380
380
- Add each {future} of {futures} on {result} to {graph} via the same procedure
381
381
as above.
382
382
- Let {futuresToRelease} be the set of completed Future nodes in {graph}
383
- completing a Deferred Fragment root node where all of the sibling Futures
384
- are also complete.
383
+ either completing a Stream root node, or completing a Deferred Fragment root
384
+ node where all of the sibling Futures are also complete.
385
385
- If {futuresToRelease} is empty, continue to the next completed child Future
386
386
node in {graph}.
387
387
- Initialize {incremental} to an empty lists.
@@ -397,9 +397,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
397
397
nodes.
398
398
- Prune root nodes of {graph} containing no direct child Futures, as above.
399
399
- Let {hasNext} be {false} if {graph} is empty.
400
- - Let {incrementalResult} be an unordered map containing {hasNext}.
401
- - If {incremental} is not empty, set the corresponding entry on
402
- {incrementalResult} to {incremental}.
400
+ - Let {incrementalResult} be an unordered map containing {incremental} and
401
+ {hasNext}.
403
402
- If {completed} is not empty, set the corresponding entry on
404
403
{incrementalResult} to {completed}.
405
404
- Let {newPendingResults} be the set of new root nodes in {graph}, promoted by
@@ -409,7 +408,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
409
408
- Set the corresponding entry on {incrementalResult} to {pending}.
410
409
- Yield {incrementalResult}.
411
410
- Emit events on {eventEmitter} signalling the release of each of the Deferred
412
- Fragments in {newPendingResults} as pending.
411
+ Fragments in {newPendingResults} as pending, as well as each of the {items}
412
+ entries on the Futures in {futuresToRelease}.
413
413
- Complete this incremental result stream.
414
414
415
415
GetPending(newPendingResults):
@@ -422,8 +422,21 @@ GetPending(newPendingResults):
422
422
- Append {pendingEntry} to {pending}.
423
423
- Return {pending}.
424
424
425
+ FutureCompletedWithoutData(completedFuture, result):
426
+
427
+ - If {completedFuture} incrementally completes Deferred Fragments:
428
+ - If {data} on {result} is {null}, return {true}.
429
+ - Otherwise:
430
+ - If {items} on {result} is not defined or {null}, return {true}.
431
+ - Return {false}.
432
+
425
433
GetIncrementalEntry(future, graph):
426
434
435
+ - If {future} completes a Stream:
436
+ - Let {stream} be the Stream incrementally completed by {future}.
437
+ - Let {items} and {errors} be the corresponding entries on {result}.
438
+ - Let {id} be the unique identifier for {stream}.
439
+ - Return an unordered map containing {id}, {items}, and {errors}.
427
440
- Let {deferredFragments} be the Deferred Fragments incrementally completed by
428
441
{future} at {path}.
429
442
- Let {result} be the result of {future}.
@@ -967,17 +980,86 @@ CompleteListValue(innerType, fieldDetailsList, result, variableValues,
967
980
eventEmitter, path, deferUsageSet, deferMap):
968
981
969
982
- Initialize {items} and {futures} to empty lists.
970
- - Let {index} be {0}.
971
- - For each {resultItem} of {result}:
983
+ - Let {fieldDetails} be the first entry in {fieldDetailsList}.
984
+ - Let {field} be the corresponding entry on {fieldDetails}.
985
+ - If {field} provides the directive ` @stream ` and its {if} argument is not
986
+ {false} and is not a variable in {variableValues} with the value {false} and
987
+ {innerType} is the outermost inner type of the list type defined for
988
+ {fieldDetailsList}:
989
+ - Let {streamDirective} be that directive.
990
+ - If this execution is for a subscription operation, raise a _ field error_ .
991
+ - Let {initialCount} be the value or variable provided to {streamDirective}'s
992
+ {initialCount} argument.
993
+ - If {initialCount} is less than zero, raise a _ field error_ .
994
+ - Let {label} be the value or variable provided to {streamDirective}'s {label}
995
+ argument.
996
+ - Let {iterator} be an iterator for {result}.
997
+ - Let {index} be zero.
998
+ - While {result} is not closed:
999
+ - If {streamDirective} is defined and {index} is greater than or equal to
1000
+ {initialCount}:
1001
+ - Initialize {parents} to an empty list.
1002
+ - For each {deferUsage} in {deferUsageSet}:
1003
+ - Let {parent} be the entry in {deferMap} for {deferUsage}.
1004
+ - Append {parent} to {parents}.
1005
+ - Let {stream} be an unordered map containing {parents}, {path}, and
1006
+ {label}.
1007
+ - Let {streamFieldDetails} be the result of
1008
+ {GetStreamFieldDetailsList(fieldDetailsList)}.
1009
+ - Let {future} represent the future execution of {ExecuteStreamField(stream,
1010
+ iterator, streamFieldDetailsList, index, innerType, variableValues,
1011
+ eventEmitter)}.
1012
+ - Defer the execution of {future} until {stream} is released as pending, as
1013
+ signalled by {eventEmitter}, or if early execution is desired, following
1014
+ any implementation specific deferral, whichever occurs first.
1015
+ - Append {future} to {futures}.
1016
+ - Return {items} and {futures}.
1017
+ - Wait for the next item from {result} via the {iterator}.
1018
+ - If an item is not retrieved because of an error, raise a _ field error_ .
1019
+ - Let {item} be the item retrieved from {result}.
972
1020
- Let {itemPath} be {path} with {index} appended.
973
1021
- Let {completedItem} and {itemFutures} be the result of calling
974
1022
{CompleteValue(innerType, fieldDetailsList, item, variableValues,
975
1023
eventEmitter, itemPath)}.
976
1024
- Append {completedItem} to {items}.
977
1025
- Append all items in {itemFutures} to {futures}.
978
- - Increment {index} by {1}.
979
1026
- Return {items} and {futures}.
980
1027
1028
+ GetStreamFieldDetailsList(fieldDetailsList):
1029
+
1030
+ - Let {streamFields} be an empty list.
1031
+ - For each {fieldDetails} in {fieldDetailsList}:
1032
+ - Let {field} be the corresponding entry on {fieldDetails}.
1033
+ - Let {newFieldDetails} be a new Field Details record created from {field}.
1034
+ - Append {newFieldDetails} to {streamFields}.
1035
+ - Return {streamFields}.
1036
+
1037
+ #### Execute Stream Field
1038
+
1039
+ ExecuteStreamField(stream, iterator, fieldDetailsList, index, innerType,
1040
+ variableValues, eventEmitter):
1041
+
1042
+ - Let {path} be the corresponding entry on {stream}.
1043
+ - Let {itemPath} be {path} with {index} appended.
1044
+ - Wait for the next item from {iterator}.
1045
+ - If {iterator} is closed, complete this data stream and return.
1046
+ - Let {item} be the next item retrieved via {iterator}.
1047
+ - Let {nextIndex} be {index} plus one.
1048
+ - Let {completedItem} and {futures} be the result of {CompleteValue(innerType,
1049
+ fields, item, variableValues, itemPath)}.
1050
+ - Initialize {items} to an empty list.
1051
+ - Append {completedItem} to {items}.
1052
+ - Let {errors} be the list of all _ field error_ raised while completing the
1053
+ item.
1054
+ - Let {future} represent the future execution of {ExecuteStreamField(stream,
1055
+ path, iterator, fieldDetailsList, nextIndex, innerType, variableValues,
1056
+ eventEmitter)}.
1057
+ - Defer the execution of {future} until {items} is released, or if early
1058
+ execution is desired, following any implementation specific deferral,
1059
+ whichever occurs first.
1060
+ - Append {future} to {futures}.
1061
+ - Return an unordered map containing {items}, {errors}, and {futures}.
1062
+
981
1063
** Coercing Results**
982
1064
983
1065
The primary purpose of value completion is to ensure that the values returned by
0 commit comments