Skip to content

Commit e933424

Browse files
committed
add descriptions and fix bug within GetNewRootNodes, it needs the old root nodes before the graph was adjusted
1 parent 8292813 commit e933424

File tree

1 file changed

+77
-14
lines changed

1 file changed

+77
-14
lines changed

spec/Section 6 -- Execution.md

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -351,14 +351,50 @@ incremental portion of the Execution Plan.
351351
### Yielding Incremental Results
352352

353353
The procedure for yielding incremental results is specified by the
354-
{YieldIncrementalResults()} algorithm.
354+
{YieldIncrementalResults()} algorithm. The incremental state is stored within a
355+
graph, with root nodes representing the currently pending delivery groups.
356+
357+
For example, given the following operation:
358+
359+
```graphql example
360+
{
361+
...SlowFragment @defer
362+
fastField
363+
}
364+
365+
fragment SlowFragment on Query {
366+
...SlowestFragment @defer
367+
slowField
368+
}
369+
370+
fragment SlowestFragment on Query {
371+
slowestField
372+
}
373+
```
374+
375+
A valid GraphQL executor deferring `SlowFragment` must include a `pending` entry
376+
to that effect within the initial result, while the `pending` entry for
377+
`SlowestFragment` should be delivered together with `SlowFragment`.
378+
379+
Delivery group nodes may have three different types of child nodes:
380+
381+
1. Other delivery group nodes, i.e. the node representing `SlowFragment` should
382+
have a child node representing `SlowestFragment`.
383+
2. Pending incremental data nodes, i.e. the node for `SlowFragment` should
384+
initially have a node for `slowField`.
385+
3. Completed incremental data nodes, i.e. when `slowField` is completed, the
386+
pending incremental data node for `slowField` should be replaced with a node
387+
representing the completed data.
388+
389+
The {YieldIncrementalResults()} algorithm is responsible for updating the graph
390+
as it yields the incremental results.
355391

356392
YieldIncrementalResults(data, errors, incrementalDataRecords):
357393

358394
- Let {graph} be the result of {GraphFromRecords(incrementalDataRecords)}.
359395
- Let {rootNodes} be the result of {GetNewRootNodes(graph)}.
360396
- Update {graph} to the subgraph rooted at nodes in {rootNodes}.
361-
- Yield the result of {GetInitialResult(data, errors, pendingResults)}.
397+
- Yield the result of {GetInitialResult(data, errors, rootNodes)}.
362398
- For each completed child Pending Incremental Data node of a root node in
363399
{graph}:
364400
- Let {incrementalDataRecord} be the Pending Incremental Data for that node;
@@ -370,7 +406,7 @@ YieldIncrementalResults(data, errors, incrementalDataRecords):
370406
- Append {GetCompletedEntry(parent, errors)} to {completed}.
371407
- Remove {node} and all of its descendant nodes from {graph}, except for
372408
any descendant Incremental Data Record nodes with other parents.
373-
- Yield the result of {GetIncrementalResult(graph, completed)}.
409+
- Yield the result of {GetSubsequentResult(graph, completed)}.
374410
- Continue to the next completed Pending Incremental Data node.
375411
- Replace {node} in {graph} with a new node corresponding to the Completed
376412
Incremental Data for {result}.
@@ -394,11 +430,11 @@ YieldIncrementalResults(data, errors, incrementalDataRecords):
394430
- Append {GetCompletedEntry(completedDeferredFragment)} to {completed}.
395431
- Remove {completedDeferredFragment} from {graph}, promoting its child
396432
Deferred Fragment nodes to root nodes.
397-
- Let {newRootNodes} be the result of {GetNewRootNodes(graph)}.
433+
- Let {newRootNodes} be the result of {GetNewRootNodes(graph, rootNodes)}.
398434
- Add all nodes in {newRootNodes} to {rootNodes}.
399435
- Update {graph} to the subgraph rooted at nodes in {rootNodes}.
400436
- Let {pending} be the result of {GetPendingEntry(newRootNodes)}.
401-
- Yield the result of {GetIncrementalResult(graph, incremental, completed,
437+
- Yield the result of {GetSubsequentResult(graph, incremental, completed,
402438
pending)}.
403439
- Complete this incremental result stream.
404440

@@ -415,35 +451,55 @@ GraphFromRecords(incrementalDataRecords, graph):
415451
to {newGraph}, or the {parent} is not defined.
416452
- Return {newGraph}.
417453

418-
GetNewRootNodes(graph):
454+
The {GetNewRootNodes()} algorithm is responsible for determining the new root
455+
nodes that must be reported as pending. Any delivery groups without any
456+
execution groups should not be reported as pending, and any child delivery
457+
groups for these "empty" delivery groups should be reported as pending in their
458+
stead.
459+
460+
GetNewRootNodes(graph, oldRootNodes):
419461

420-
- Initialize {newPendingResults} to the empty set.
462+
- Initialize {newRootNodes} to the empty set.
421463
- Initialize {rootNodes} to the set of root nodes in {graph}.
422464
- For each {rootNode} of {rootNodes}:
423465
- If {rootNode} has no children Pending Incremental Data nodes:
424466
- Let {children} be the set of child Deferred Fragment nodes of {rootNode}.
425467
- Add each of the nodes in {children} to {rootNodes}.
426468
- Continue to the next {rootNode} of {rootNodes}.
427-
- Add {rootNode} to {newPendingResults}.
428-
- Return {newPendingResults}.
469+
- If {oldRootNodes} does not contain {rootNode}, add {rootNode} to
470+
{newRootNodes}.
471+
- Return {newRootNodes}.
472+
473+
Formatting of the initial result is defined by the {GetInitialResult()}
474+
algorithm. It will only be called when there is an incremental result stream,
475+
and so `hasNext` will always be set to {true}.
429476

430477
GetInitialResult(data, errors, pendingResults):
431478

432479
- Let {pending} be the result of {GetPendingEntry(pendingResults)}.
433480
- Let {hasNext} be {true}.
434481
- Return an unordered map containing {data}, {errors}, {pending}, and {hasNext}.
435482

436-
GetPendingEntry(pendingResults):
483+
Formatting the `pending` of initial and subsequentResults is defined by the
484+
{GetPendingEntry()} algorithm. Given a set of new root nodes added to the graph,
485+
{GetPendingEntry()} returns a list of formatted `pending` entries.
486+
487+
GetPendingEntry(newRootNodes):
437488

438489
- Initialize {pending} to an empty list.
439-
- For each {pendingResult} of {pendingResult}:
440-
- Let {id} be a unique identifier for {pendingResult}.
441-
- Let {path} and {label} be the corresponding entries on {pendingResult}.
490+
- For each {newRootNode} of {newRootNodes}:
491+
- Let {id} be a unique identifier for {newRootNode}.
492+
- Let {path} and {label} be the corresponding entries on {newRootNode}.
442493
- Let {pendingEntry} be an unordered map containing {id}, {path}, and {label}.
443494
- Append {pendingEntry} to {pending}.
444495
- Return {pending}.
445496

446-
GetIncrementalResult(graph, completed, incremental, pending):
497+
Formatting of subsequent incremental results is defined by the
498+
{GetSubsequentResult()} algorithm. Given the current graph, and any `completed`,
499+
`incremental`, and `pending` entries, it produces an appropriately formatted
500+
subsequent incremental response.
501+
502+
GetSubsequentResult(graph, completed, incremental, pending):
447503

448504
- Let {hasNext} be {false} if {graph} is empty, otherwise, {true}.
449505
- Let {incrementalResult} be an unordered map containing {hasNext}.
@@ -455,6 +511,10 @@ GetIncrementalResult(graph, completed, incremental, pending):
455511
- Set the corresponding entry on {incrementalResult} to {pending}.
456512
- Return {incrementalResult}.
457513

514+
Formatting of subsequent incremental results is defined by the
515+
{GetSubsequentResult()} algorithm. Execution groups are tagged with the `id` and
516+
`subPath` combination optimized to produce the shortest `subPath`.
517+
458518
GetIncrementalEntry(incrementalDataRecord, graph):
459519

460520
- Let {deferredFragments} be the Deferred Fragments incrementally completed by
@@ -470,6 +530,9 @@ GetIncrementalEntry(incrementalDataRecord, graph):
470530
- Let {id} be the unique identifier for {bestDeferredFragment}.
471531
- Return an unordered map containing {id}, {subPath}, {data}, and {errors}.
472532

533+
Formatting of completed incremental results is defined by the
534+
{GetCompletedEntry()} algorithm.
535+
473536
GetCompletedEntry(pendingResult, errors):
474537

475538
- Let {id} be the unique identifier for {pendingResult}.

0 commit comments

Comments
 (0)