Skip to content

Commit 6862323

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

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
@@ -354,14 +354,50 @@ incremental portion of the Execution Plan.
354354
### Yielding Incremental Results
355355

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

359395
YieldIncrementalResults(data, errors, incrementalDataRecords):
360396

361397
- Let {graph} be the result of {GraphFromRecords(incrementalDataRecords)}.
362398
- Let {rootNodes} be the result of {GetNewRootNodes(graph)}.
363399
- Update {graph} to the subgraph rooted at nodes in {rootNodes}.
364-
- Yield the result of {GetInitialResult(data, errors, pendingResults)}.
400+
- Yield the result of {GetInitialResult(data, errors, rootNodes)}.
365401
- For each completed child Pending Incremental Data node of a root node in
366402
{graph}:
367403
- Let {incrementalDataRecord} be the Pending Incremental Data for that node;
@@ -373,7 +409,7 @@ YieldIncrementalResults(data, errors, incrementalDataRecords):
373409
- Append {GetCompletedEntry(parent, errors)} to {completed}.
374410
- Remove {node} and all of its descendant nodes from {graph}, except for
375411
any descendant Incremental Data Record nodes with other parents.
376-
- Yield the result of {GetIncrementalResult(graph, completed)}.
412+
- Yield the result of {GetSubsequentResult(graph, completed)}.
377413
- Continue to the next completed Pending Incremental Data node.
378414
- Replace {node} in {graph} with a new node corresponding to the Completed
379415
Incremental Data for {result}.
@@ -397,11 +433,11 @@ YieldIncrementalResults(data, errors, incrementalDataRecords):
397433
- Append {GetCompletedEntry(completedDeferredFragment)} to {completed}.
398434
- Remove {completedDeferredFragment} from {graph}, promoting its child
399435
Deferred Fragment nodes to root nodes.
400-
- Let {newRootNodes} be the result of {GetNewRootNodes(graph)}.
436+
- Let {newRootNodes} be the result of {GetNewRootNodes(graph, rootNodes)}.
401437
- Add all nodes in {newRootNodes} to {rootNodes}.
402438
- Update {graph} to the subgraph rooted at nodes in {rootNodes}.
403439
- Let {pending} be the result of {GetPendingEntry(newRootNodes)}.
404-
- Yield the result of {GetIncrementalResult(graph, incremental, completed,
440+
- Yield the result of {GetSubsequentResult(graph, incremental, completed,
405441
pending)}.
406442
- Complete this incremental result stream.
407443

@@ -418,35 +454,55 @@ GraphFromRecords(incrementalDataRecords, graph):
418454
to {newGraph}, or the {parent} is not defined.
419455
- Return {newGraph}.
420456

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

423-
- Initialize {newPendingResults} to the empty set.
465+
- Initialize {newRootNodes} to the empty set.
424466
- Initialize {rootNodes} to the set of root nodes in {graph}.
425467
- For each {rootNode} of {rootNodes}:
426468
- If {rootNode} has no children Pending Incremental Data nodes:
427469
- Let {children} be the set of child Deferred Fragment nodes of {rootNode}.
428470
- Add each of the nodes in {children} to {rootNodes}.
429471
- Continue to the next {rootNode} of {rootNodes}.
430-
- Add {rootNode} to {newPendingResults}.
431-
- Return {newPendingResults}.
472+
- If {oldRootNodes} does not contain {rootNode}, add {rootNode} to
473+
{newRootNodes}.
474+
- Return {newRootNodes}.
475+
476+
Formatting of the initial result is defined by the {GetInitialResult()}
477+
algorithm. It will only be called when there is an incremental result stream,
478+
and so `hasNext` will always be set to {true}.
432479

433480
GetInitialResult(data, errors, pendingResults):
434481

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

439-
GetPendingEntry(pendingResults):
486+
Formatting the `pending` of initial and subsequentResults is defined by the
487+
{GetPendingEntry()} algorithm. Given a set of new root nodes added to the graph,
488+
{GetPendingEntry()} returns a list of formatted `pending` entries.
489+
490+
GetPendingEntry(newRootNodes):
440491

441492
- Initialize {pending} to an empty list.
442-
- For each {pendingResult} of {pendingResult}:
443-
- Let {id} be a unique identifier for {pendingResult}.
444-
- Let {path} and {label} be the corresponding entries on {pendingResult}.
493+
- For each {newRootNode} of {newRootNodes}:
494+
- Let {id} be a unique identifier for {newRootNode}.
495+
- Let {path} and {label} be the corresponding entries on {newRootNode}.
445496
- Let {pendingEntry} be an unordered map containing {id}, {path}, and {label}.
446497
- Append {pendingEntry} to {pending}.
447498
- Return {pending}.
448499

449-
GetIncrementalResult(graph, completed, incremental, pending):
500+
Formatting of subsequent incremental results is defined by the
501+
{GetSubsequentResult()} algorithm. Given the current graph, and any `completed`,
502+
`incremental`, and `pending` entries, it produces an appropriately formatted
503+
subsequent incremental response.
504+
505+
GetSubsequentResult(graph, completed, incremental, pending):
450506

451507
- Let {hasNext} be {false} if {graph} is empty, otherwise, {true}.
452508
- Let {incrementalResult} be an unordered map containing {hasNext}.
@@ -458,6 +514,10 @@ GetIncrementalResult(graph, completed, incremental, pending):
458514
- Set the corresponding entry on {incrementalResult} to {pending}.
459515
- Return {incrementalResult}.
460516

517+
Formatting of subsequent incremental results is defined by the
518+
{GetSubsequentResult()} algorithm. Execution groups are tagged with the `id` and
519+
`subPath` combination optimized to produce the shortest `subPath`.
520+
461521
GetIncrementalEntry(incrementalDataRecord, graph):
462522

463523
- Let {deferredFragments} be the Deferred Fragments incrementally completed by
@@ -473,6 +533,9 @@ GetIncrementalEntry(incrementalDataRecord, graph):
473533
- Let {id} be the unique identifier for {bestDeferredFragment}.
474534
- Return an unordered map containing {id}, {subPath}, {data}, and {errors}.
475535

536+
Formatting of completed incremental results is defined by the
537+
{GetCompletedEntry()} algorithm.
538+
476539
GetCompletedEntry(pendingResult, errors):
477540

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

0 commit comments

Comments
 (0)