Skip to content

Commit f664dc9

Browse files
committed
defers is a map, streams is a list, they are both recursively merged
1 parent c2d1693 commit f664dc9

File tree

1 file changed

+73
-43
lines changed

1 file changed

+73
-43
lines changed

spec/Section 6 -- Execution.md

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,18 @@ ExecuteQuery(query, schema, variableValues, initialValue):
131131
- Let {queryType} be the root Query type in {schema}.
132132
- Assert: {queryType} is an Object type.
133133
- Let {selectionSet} be the top level Selection Set in {query}.
134-
- Let {data}, {pendings} be the result of running
134+
- Let {data}, {defers}, {streams} be the result of running
135135
{ExecuteSelectionSet(selectionSet, queryType, initialValue, variableValues)}
136136
_normally_ (allowing parallelization).
137137
- Let {errors} be the list of all _field error_ raised while executing the
138138
selection set.
139-
- If {pendings} is empty:
139+
- If {defers} is an empty map and {streams} is an empty list:
140140
- Return an unordered map containing {data} and {errors}.
141141
- Else:
142-
- Return {IncrementalStream(data, errors, pendings, variableValues)}.
142+
- Return {IncrementalEventStream(data, errors, defers, streams,
143+
variableValues)}.
143144

144-
IncrementalStream(data, errors, pendings, variableValues):
145+
IncrementalEventStream(data, errors, defers, streams, variableValues):
145146

146147
- Let {responseStream} be a new event stream {responseStream}.
147148
- Let {hasNext} be {true}.
@@ -207,17 +208,18 @@ ExecuteMutation(mutation, schema, variableValues, initialValue):
207208
- Let {mutationType} be the root Mutation type in {schema}.
208209
- Assert: {mutationType} is an Object type.
209210
- Let {selectionSet} be the top level Selection Set in {mutation}.
210-
- Let {data}, {pendings} be the result of running
211+
- Let {data}, {defers} and {streams} be the result of running
211212
{ExecuteSelectionSet(selectionSet, mutationType, initialValue,
212213
variableValues)} _serially_.
213214
- Let {errors} be the list of all _field error_ raised while executing the
214215
selection set.
215-
- If {pendings} is empty:
216+
- If {defers} is an empty map and {streams} is an empty list:
216217
- Return an unordered map containing {data} and {errors}.
217218
- Else:
218219
- Note: this places the defers after _all_ the mutations. This may not be
219220
desired; we should discuss.
220-
- Return {IncrementalStream(data, errors, pendings, variableValues)}.
221+
- Return {IncrementalEventStream(data, errors, defers, streams,
222+
variableValues)}.
221223

222224
### Subscription
223225

@@ -366,17 +368,18 @@ ExecuteSubscriptionEvent(subscription, schema, variableValues, initialValue):
366368
- Let {subscriptionType} be the root Subscription type in {schema}.
367369
- Assert: {subscriptionType} is an Object type.
368370
- Let {selectionSet} be the top level Selection Set in {subscription}.
369-
- Let {data}, {pendings} be the result of running
371+
- Let {data}, {defers} and {streams} be the result of running
370372
{ExecuteSelectionSet(selectionSet, subscriptionType, initialValue,
371373
variableValues)} _normally_ (allowing parallelization).
372374
- Let {errors} be the list of all _field error_ raised while executing the
373375
selection set.
374-
- If {pendings} is empty:
376+
- If {defers} is an empty map and {streams} is an empty list:
375377
- Return an unordered map containing {data} and {errors}.
376378
- Else:
377379
- Note: this places the defers after _all_ the mutations. This may not be
378380
desired; we should discuss.
379-
- Return {IncrementalStream(data, errors, pendings, variableValues)}.
381+
- Return {IncrementalEventStream(data, errors, defers, streams,
382+
variableValues)}.
380383

381384
Note: The {ExecuteSubscriptionEvent()} algorithm is intentionally similar to
382385
{ExecuteQuery()} since this is how each event result is produced.
@@ -402,26 +405,35 @@ First, the selection set is turned into a grouped field set; then, each
402405
represented field in the grouped field set produces an entry into a response
403406
map.
404407

405-
ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues):
408+
ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues,
409+
parentPath):
406410

411+
- If {parentPath} is not provided, initialize it to an empty list.
407412
- Let {groupedFieldSet} be the result of {CollectFields(objectType,
408-
selectionSet, variableValues)}.
413+
selectionSet, variableValues, parentPath)}.
409414
- Initialize {resultMap} to an empty ordered map.
410-
- Let {deferred} be an empty list.
415+
- Let {defers} be an empty unordered map.
411416
- Let {streams} be an empty list.
412417
- For each {groupedFieldSet} as {responseKey} and {fieldDetails}:
413418
- Let {fieldDetail} be the first entry in {fieldDetails}.
414419
- Let {field} be the value for the key {field} in {fieldDetail}.
420+
- Let {path} be the value for the key {path} in {fieldDetail}.
415421
- Let {fieldName} be the name of {field}. Note: This value is unaffected if an
416422
alias is used.
417423
- Let {fieldType} be the return type defined for the field {fieldName} of
418424
{objectType}.
419425
- If {fieldType} is defined:
420426
- If every entry in {fieldDetails} has {isDeferred} set to {true}:
421-
- Add {fieldDetails} to {deferred}.
427+
- Let {deferredGroupForPath} be the list in {defers} for {path}; if no
428+
such list exists, create it as an empty list.
429+
- Append {fieldDetails} to {deferredGroupForPath}.
422430
- Else:
423-
- Let {responseValue} be {ExecuteField(objectType, objectValue, fieldType,
424-
fieldDetails, variableValues)}.
431+
- Let {responseValue}, {childDefers}, {childStreams} be
432+
{ExecuteField(objectType, objectValue, fieldType, fieldDetails,
433+
variableValues, path)}.
434+
- Add the entries of {childDefers} into {defers}. Note: {childDefers} and
435+
{defers} will never have keys in common.
436+
- For each entry {stream} in {childStreams}, append {stream} to {streams}.
425437
- If {responseValue} is not null and {fieldType} is a list type and
426438
{field} provides the directive `@stream`, let {streamDirective} be that
427439
directive. If {streamDirective}'s {if} argument is not {false} and is
@@ -438,15 +450,12 @@ ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues):
438450
{responesValue}, and {remainingValues} be the remainder.
439451
- Set {initialValues} as the value for {responseKey} in {resultMap}.
440452
- If there are (or may be) values in {remainingValues}:
441-
- TODO: add {remainingValues} to {streams} via some mechanism...
453+
- Let {streamDetails} be an unordered map containing {path},
454+
{remainingValues} and {fieldDetails}.
455+
- Append {streamDetails} to {streams}.
442456
- Else:
443457
- Set {responseValue} as the value for {responseKey} in {resultMap}.
444-
- Let {pendings} be an empty list.
445-
- If {deferred} is not empty:
446-
- Add a single entry to {pendings}.
447-
- For each {stream} in {streams}:
448-
- Add {something} to {pendings}.
449-
- Return {resultMap} and {pendings}.
458+
- Return {resultMap}, {defers} and {streams}.
450459

451460
Note: {resultMap} is ordered by which fields appear first in the operation. This
452461
is explained in greater detail in the Field Collection section below.
@@ -591,8 +600,9 @@ is maintained through execution, ensuring that fields appear in the executed
591600
response in a stable and predictable order.
592601

593602
CollectFields(objectType, selectionSet, variableValues, isDeferred,
594-
visitedFragments):
603+
visitedFragments, parentPath):
595604

605+
- If {parentPath} is not provided, initialize it to an empty list.
596606
- If {isDeferred} is not provided, initialize it to {false}.
597607
- If {visitedFragments} is not provided, initialize it to the empty set.
598608
- Initialize {groupedFields} to an empty ordered map of lists.
@@ -611,9 +621,11 @@ visitedFragments):
611621
- Let {field} be {selection}.
612622
- Let {responseKey} be the response key of {field} (the alias if defined,
613623
otherwise the field name).
624+
- Let {path} be a copy of {parentPath} with {responseKey} appended.
614625
- Let {groupForResponseKey} be the list in {groupedFields} for
615626
{responseKey}; if no such list exists, create it as an empty list.
616-
- Let {fieldDetail} be an unordered map containing {field} and {isDeferred}.
627+
- Let {fieldDetail} be an unordered map containing {field}, {path} and
628+
{isDeferred}.
617629
- Append {fieldDetail} to the {groupForResponseKey}.
618630
- If {selection} is a {FragmentSpread}:
619631
- Let {fragmentSpreadName} be the name of {selection}.
@@ -636,7 +648,7 @@ visitedFragments):
636648
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
637649
- Let {fragmentGroupedFieldSet} be the result of calling
638650
{CollectFields(objectType, fragmentSelectionSet, variableValues,
639-
fragmentIsDeferred, visitedFragments)}.
651+
fragmentIsDeferred, visitedFragments, parentPath)}.
640652
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
641653
- Let {responseKey} be the response key shared by all fields in
642654
{fragmentGroup}.
@@ -657,7 +669,7 @@ visitedFragments):
657669
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
658670
- Let {fragmentGroupedFieldSet} be the result of calling
659671
{CollectFields(objectType, fragmentSelectionSet, variableValues,
660-
fragmentIsDeferred, visitedFragments)}.
672+
fragmentIsDeferred, visitedFragments, parentPath)}.
661673
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
662674
- Let {responseKey} be the response key shared by all fields in
663675
{fragmentGroup}.
@@ -689,16 +701,17 @@ coerces any provided argument values, then resolves a value for the field, and
689701
finally completes that value either by recursively executing another selection
690702
set or coercing a scalar value.
691703

692-
ExecuteField(objectType, objectValue, fieldType, fields, variableValues):
704+
ExecuteField(objectType, objectValue, fieldType, fields, variableValues, path):
693705

694706
- Let {field} be the first entry in {fields}.
695707
- Let {fieldName} be the field name of {field}.
696708
- Let {argumentValues} be the result of {CoerceArgumentValues(objectType, field,
697709
variableValues)}
698710
- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName,
699711
argumentValues)}.
700-
- Return the result of {CompleteValue(fieldType, fields, resolvedValue,
701-
variableValues)}.
712+
- Let {responseValue}, {defers} and {streams} be the result of
713+
{CompleteValue(fieldType, fields, resolvedValue, variableValues, path)}.
714+
- Return {responseValue}, {defers} and {streams}.
702715

703716
### Coercing Field Arguments
704717

@@ -785,34 +798,51 @@ After resolving the value for a field, it is completed by ensuring it adheres to
785798
the expected return type. If the return type is another Object type, then the
786799
field execution process continues recursively.
787800

788-
CompleteValue(fieldType, fields, result, variableValues):
801+
CompleteValue(fieldType, fields, result, variableValues, path):
789802

790-
- TODO: overhaul for incremental!
791803
- If the {fieldType} is a Non-Null type:
792804
- Let {innerType} be the inner type of {fieldType}.
793-
- Let {completedResult} be the result of calling {CompleteValue(innerType,
794-
fields, result, variableValues)}.
805+
- Let {completedResult}, {defers} and {streams} be the result of calling
806+
{CompleteValue(innerType, fields, result, variableValues, path)}.
795807
- If {completedResult} is {null}, raise a _field error_.
796-
- Return {completedResult}.
808+
- Return {completedResult}, {defers} and {streams}.
797809
- If {result} is {null} (or another internal value similar to {null} such as
798-
{undefined}), return {null}.
810+
{undefined}):
811+
- Let {completedResult} be {null}.
812+
- Let {defers} be an empty unordered map.
813+
- Let {streams} be an empty list.
814+
- Return {completedResult}, {defers} and {streams}.
799815
- If {fieldType} is a List type:
800816
- If {result} is not a collection of values, raise a _field error_.
801817
- Let {innerType} be the inner type of {fieldType}.
802-
- Return a list where each list item is the result of calling
803-
{CompleteValue(innerType, fields, resultItem, variableValues)}, where
804-
{resultItem} is each item in {result}.
818+
- Let {defers} be an empty unordered map.
819+
- Let {streams} be an empty list.
820+
- Let {completedResult} be an empty list.
821+
- For each entry {resultItem} at zero-based index {resultIndex} in {result}:
822+
- Let {listItemPath} be a copy of {path} with {resultIndex} appended.
823+
- Let {completedItemResult}, {childDefers} and {childStreams} be the result
824+
of calling {CompleteValue(innerType, fields, resultItem, variableValues,
825+
listItemPath)}.
826+
- Add the entries of {childDefers} into {defers}. Note: {childDefers} and
827+
{defers} will never have keys in common.
828+
- For each entry {stream} in {childStreams}, append {stream} to {streams}.
829+
- Append {completedItemResult} to {completedResult}.
830+
- Return {completedResult}, {defers} and {streams}.
805831
- If {fieldType} is a Scalar or Enum type:
806-
- Return the result of {CoerceResult(fieldType, result)}.
832+
- Let {completedResult} be the result of {CoerceResult(fieldType, result)}.
833+
- Let {defers} be an empty unordered map.
834+
- Let {streams} be an empty list.
835+
- Return {completedResult}, {defers} and {streams}.
807836
- If {fieldType} is an Object, Interface, or Union type:
808837
- If {fieldType} is an Object type.
809838
- Let {objectType} be {fieldType}.
810839
- Otherwise if {fieldType} is an Interface or Union type.
811840
- Let {objectType} be {ResolveAbstractType(fieldType, result)}.
812841
- Let {subSelectionSet} be the result of calling {MergeSelectionSets(fields)}.
813-
- Return the result of evaluating {ExecuteSelectionSet(subSelectionSet,
814-
objectType, result, variableValues)} _normally_ (allowing for
815-
parallelization).
842+
- Let {completedResult}, {defers} and {streams} be the result of evaluating
843+
{ExecuteSelectionSet(subSelectionSet, objectType, result, variableValues,
844+
path)} _normally_ (allowing for parallelization).
845+
- Return {completedResult}, {defers} and {streams}.
816846

817847
**Coercing Results**
818848

0 commit comments

Comments
 (0)