Skip to content

Commit e9f3b78

Browse files
committed
Introduce @stream directive
1 parent 67d084e commit e9f3b78

File tree

1 file changed

+92
-10
lines changed

1 file changed

+92
-10
lines changed

Diff for: spec/Section 6 -- Execution.md

+92-10
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
366366
{newPendingResults} as pending.
367367
- For each completed child Future node of a root node in {graph}:
368368
- Let {completedFuture} be that Future; let {result} be its result.
369-
- If {data} on {result} is {null}:
369+
- If {FutureCompletedWithoutData(completedFuture, result)} is {true}:
370370
- Initialize {completed} to an empty list.
371371
- Let {parents} be the parents of {completedFuture}.
372372
- Initialize {completed} to an empty list.
@@ -380,8 +380,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
380380
- Add each {future} of {futures} on {result} to {graph} via the same procedure
381381
as above.
382382
- 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.
385385
- If {futuresToRelease} is empty, continue to the next completed child Future
386386
node in {graph}.
387387
- Initialize {incremental} to an empty lists.
@@ -397,9 +397,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
397397
nodes.
398398
- Prune root nodes of {graph} containing no direct child Futures, as above.
399399
- 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}.
403402
- If {completed} is not empty, set the corresponding entry on
404403
{incrementalResult} to {completed}.
405404
- Let {newPendingResults} be the set of new root nodes in {graph}, promoted by
@@ -409,7 +408,8 @@ YieldIncrementalResults(data, errors, futures, eventEmitter):
409408
- Set the corresponding entry on {incrementalResult} to {pending}.
410409
- Yield {incrementalResult}.
411410
- 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}.
413413
- Complete this incremental result stream.
414414

415415
GetPending(newPendingResults):
@@ -422,8 +422,21 @@ GetPending(newPendingResults):
422422
- Append {pendingEntry} to {pending}.
423423
- Return {pending}.
424424

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+
425433
GetIncrementalEntry(future, graph):
426434

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}.
427440
- Let {deferredFragments} be the Deferred Fragments incrementally completed by
428441
{future} at {path}.
429442
- Let {result} be the result of {future}.
@@ -967,17 +980,86 @@ CompleteListValue(innerType, fieldDetailsList, result, variableValues,
967980
eventEmitter, path, deferUsageSet, deferMap):
968981

969982
- 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}.
9721020
- Let {itemPath} be {path} with {index} appended.
9731021
- Let {completedItem} and {itemFutures} be the result of calling
9741022
{CompleteValue(innerType, fieldDetailsList, item, variableValues,
9751023
eventEmitter, itemPath)}.
9761024
- Append {completedItem} to {items}.
9771025
- Append all items in {itemFutures} to {futures}.
978-
- Increment {index} by {1}.
9791026
- Return {items} and {futures}.
9801027

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+
9811063
**Coercing Results**
9821064

9831065
The primary purpose of value completion is to ensure that the values returned by

0 commit comments

Comments
 (0)