@@ -329,12 +329,12 @@ ExecuteRootSelectionSet(variableValues, initialValue, objectType, selectionSet,
329329serial):
330330
331331- If {serial} is not provided, initialize it to {false}.
332- - Let {groupedFieldSet} and {newDeferUsages} be the result of
333- {CollectFields(objectType, selectionSet, variableValues)}.
332+ - Let {groupedFieldSet} be the result of {CollectFields(objectType,
333+ selectionSet, variableValues)}.
334334- Let {executionPlan} be the result of {BuildExecutionPlan(groupedFieldSet)}.
335335- Let {data} and {incrementalDataRecords} be the result of
336- {ExecuteExecutionPlan(newDeferUsages, executionPlan, objectType, initialValue,
337- variableValues, serial)}.
336+ {ExecuteExecutionPlan(executionPlan, objectType, initialValue, variableValues ,
337+ serial)}.
338338- Let {errors} be the list of all _ field error_ raised while completing {data}.
339339- If {incrementalDataRecords} is empty, return an unordered map containing
340340 {data} and {errors}.
@@ -405,11 +405,28 @@ GraphFromRecords(incrementalDataRecords, graph):
405405- Let {newGraph} be a new directed acyclic graph containing all of the nodes and
406406 edges in {graph}.
407407- For each {incrementalDataRecord} of {incrementalDataRecords}:
408+ - Let {deferUsageSet} be the Defer Usages incrementally completed by
409+ {incrementalDataRecord} at {path}.
410+ - For each {deferUsage} of {deferUsageSet}:
411+ - If {newGraph} does not contain a Deferred Fragment node representing the
412+ completion of {deferUsage} at {path}, reset {newGraph} to the result of
413+ {GraphWithDeferredFragmentRecord(deferUsage, path, newGraph)}.
408414 - Add {incrementalDataRecord} to {newGraph} as a new Pending Data node
409- directed from the {pendingResults} that it completes, adding each of
410- {pendingResults} to {newGraph} as a new node directed from its {parent},
411- recursively adding each {parent} until {incrementalDataRecord} is connected
412- to {newGraph}, or the {parent} is not defined.
415+ directed from the {deferredFragments} that it completes.
416+ - Return {newGraph}.
417+
418+ GraphWithDeferredFragmentRecord(deferUsage, path, graph):
419+
420+ - Let {parentDeferUsage} and {label} be the corresponding entries on
421+ {deferUsage}.
422+ - If {parentDeferUsage} is defined and {graph} does not contain a Deferred
423+ Fragment node representing the completion of {parentDeferUsage} at {path}, let
424+ {newGraph} be the result of {GraphWithDeferredFragmentRecord(parentDeferUsage,
425+ path, newGraph)}; otherwise, let {newGraph} be a new directed acyclic graph
426+ containing all of the nodes and edges in {graph}.
427+ - Let {deferredFragment} be a new unordered map containing {path} and {label}.
428+ - Add {deferredFragment} to {newGraph} as a new Deferred Fragment node directed
429+ from {parent}.
413430- Return {newGraph}.
414431
415432GetNonEmptyNewPending(graph):
@@ -454,8 +471,8 @@ GetIncrementalResult(graph, incremental, completed, pending):
454471
455472GetIncrementalEntry(incrementalDataRecord, graph):
456473
457- - Let {deferredFragments} be the Deferred Fragments incrementally completed by
458- {incrementalDataRecord} at {path}.
474+ - Let {deferredFragments} be the Deferred Fragment nodes within {graph}
475+ incrementally completed by {incrementalDataRecord} at {path}.
459476- Let {result} be the result of {incrementalDataRecord}.
460477- Let {data} and {errors} be the corresponding entries on {result}.
461478- Let {releasedDeferredFragments} be the members of {deferredFragments} that are
@@ -496,67 +513,48 @@ To execute a execution plan, the object value being evaluated and the object
496513type need to be known, as well as whether the non-deferred grouped field set
497514must be executed serially, or may be executed in parallel.
498515
499- ExecuteExecutionPlan(newDeferUsages, executionPlan, objectType, objectValue,
500- variableValues, serial, path, deferUsageSet, deferMap ):
516+ ExecuteExecutionPlan(executionPlan, objectType, objectValue, variableValues ,
517+ serial, path, deferUsageSet):
501518
502519- If {path} is not provided, initialize it to an empty list.
503- - Let {newDeferMap} be the result of {GetNewDeferMap(newDeferUsages, path,
504- deferMap)}.
505520- Let {groupedFieldSet} and {newGroupedFieldSets} be the corresponding entries
506521 on {executionPlan}.
507522- Allowing for parallelization, perform the following steps:
508523 - Let {data} and {nestedIncrementalDataRecords} be the result of running
509524 {ExecuteGroupedFieldSet(groupedFieldSet, objectType, objectValue,
510- variableValues, path, deferUsageSet, newDeferMap )} _ serially_ if {serial} is
511- {true}, _ normally_ (allowing parallelization) otherwise.
525+ variableValues, path, deferUsageSet)} _ serially_ if {serial} is {true},
526+ _ normally_ (allowing parallelization) otherwise.
512527 - Let {incrementalDataRecords} be the result of
513528 {CollectExecutionGroups(objectType, objectValue, variableValues,
514529 newGroupedFieldSets, path, newDeferMap)}.
515530- Append all items in {nestedIncrementalDataRecords} to
516531 {incrementalDataRecords}.
517532- Return {data} and {incrementalDataRecords}.
518533
519- GetNewDeferMap(newDeferUsages, path, deferMap):
520-
521- - If {newDeferUsages} is empty, return {deferMap}:
522- - Let {newDeferMap} be a new unordered map containing all entries in {deferMap}.
523- - For each {deferUsage} in {newDeferUsages}:
524- - Let {parentDeferUsage} and {label} be the corresponding entries on
525- {deferUsage}.
526- - Let {parent} be the entry in {deferMap} for {parentDeferUsage}.
527- - Let {newDeferredFragment} be an unordered map containing {parent}, {path}
528- and {label}.
529- - Set the entry for {deferUsage} in {newDeferMap} to {newDeferredFragment}.
530- - Return {newDeferMap}.
531-
532534CollectExecutionGroups(objectType, objectValue, variableValues,
533- newGroupedFieldSets, path, deferMap ):
535+ newGroupedFieldSets, path):
534536
535537- Initialize {incrementalDataRecords} to an empty list.
536538- For each {deferUsageSet} and {groupedFieldSet} in {newGroupedFieldSets}:
537- - Let {deferredFragments} be an empty list.
538- - For each {deferUsage} in {deferUsageSet}:
539- - Let {deferredFragment} be the entry for {deferUsage} in {deferMap}.
540- - Append {deferredFragment} to {deferredFragments}.
541539 - Let {incrementalDataRecord} represent the future execution of
542540 {ExecuteExecutionGroup(groupedFieldSet, objectType, objectValue,
543- variableValues, deferredFragments, path, deferUsageSet, deferMap )},
544- incrementally completing {deferredFragments } at {path}.
541+ variableValues, path, deferUsageSet)}, incrementally completing
542+ {deferUsageSet } at {path}.
545543 - Append {incrementalDataRecord} to {incrementalDataRecords}.
546544 - Schedule initiation of execution of {incrementalDataRecord} following any
547545 implementation specific deferral.
548546- Return {incrementalDataRecords}.
549547
550548Note: {incrementalDataRecord} can be safely initiated without blocking
551- higher-priority data once any of {deferredFragments} are released as pending.
549+ higher-priority data once any of {deferUsageSet} at {path} are released as
550+ pending.
552551
553552ExecuteExecutionGroup(groupedFieldSet, objectType, objectValue, variableValues,
554- path, deferUsageSet, deferMap ):
553+ path, deferUsageSet):
555554
556555- Let {data} and {incrementalDataRecords} be the result of running
557556 {ExecuteGroupedFieldSet(groupedFieldSet, objectType, objectValue,
558- variableValues, path, deferUsageSet, deferMap)} _ normally_ (allowing
559- parallelization).
557+ variableValues, path, deferUsageSet)} _ normally_ (allowing parallelization).
560558- Let {errors} be the list of all _ field error_ raised while completing {data}.
561559- Return an unordered map containing {data}, {errors}, and
562560 {incrementalDataRecords}.
@@ -571,7 +569,7 @@ Each represented field in the grouped field set produces an entry into a
571569response map.
572570
573571ExecuteGroupedFieldSet(groupedFieldSet, objectType, objectValue, variableValues,
574- path, deferUsageSet, deferMap ):
572+ path, deferUsageSet):
575573
576574- Initialize {resultMap} to an empty ordered map.
577575- Initialize {incrementalDataRecords} to an empty list.
@@ -583,7 +581,7 @@ path, deferUsageSet, deferMap):
583581 - If {fieldType} is defined:
584582 - Let {responseValue} and {fieldIncrementalDataRecords} be the result of
585583 {ExecuteField(objectType, objectValue, fieldType, fields, variableValues,
586- path, deferUsageSet, deferMap )}.
584+ path, deferUsageSet)}.
587585 - Set {responseValue} as the value for {responseKey} in {resultMap}.
588586 - Append all items in {fieldIncrementalDataRecords} to
589587 {incrementalDataRecords}.
@@ -747,6 +745,8 @@ Defer Usages contain the following information:
747745 any, otherwise {undefined}.
748746- {parentDeferUsage}: a Defer Usage corresponding to the ` @defer ` directive
749747 enclosing this ` @defer ` directive, if any, otherwise {undefined}.
748+ - {depth}: the depth within the overall result corresponding to the deferred
749+ fields.
750750
751751The {parentDeferUsage} entry is used to build distinct Execution Groups as
752752discussed within the Execution Plan Generation section below.
@@ -761,18 +761,12 @@ A Grouped Field Set is an ordered map of keys to lists of Field Details. The
761761keys are the same as that of the response, the alias for the field, if defined,
762762otherwise the field name.
763763
764- The {CollectFields()} algorithm returns:
765-
766- - {groupedFieldSet}: the Grouped Field Set for the fields in the selection set.
767- - {newDeferUsages}: a list of new Defer Usages encountered during this field
768- collection.
769-
770- CollectFields(objectType, selectionSet, variableValues, deferUsage,
764+ CollectFields(objectType, selectionSet, variableValues, deferUsage, depth,
771765visitedFragments):
772766
767+ - If {depth} is not provided, initialize it to {0}.
773768- If {visitedFragments} is not provided, initialize it to the empty set.
774769- Initialize {groupedFields} to an empty ordered map of lists.
775- - Initialize {newDeferUsages} to an empty list.
776770- For each {selection} in {selectionSet}:
777771 - If {selection} provides the directive ` @skip ` , let {skipDirective} be that
778772 directive.
@@ -816,19 +810,18 @@ visitedFragments):
816810 - If {deferDirective} is defined:
817811 - Let {label} be the corresponding entry on {deferDirective}.
818812 - Let {parentDeferUsage} be {deferUsage}.
819- - Let {fragmentDeferUsage} be an unordered map containing {label} and
820- {parentDeferUsage}.
813+ - Let {fragmentDeferUsage} be an unordered map containing {label},
814+ {parentDeferUsage}, and {depth} .
821815 - Otherwise, let {fragmentDeferUsage} be {deferUsage}.
822- - Let {fragmentGroupedFieldSet} and {fragmentNewDeferUsages} be the result
823- of calling {CollectFields(objectType, fragmentSelectionSet,
824- variableValues, fragmentDeferUsage , visitedFragments)}.
816+ - Let {fragmentGroupedFieldSet} be the result of calling
817+ {CollectFields(objectType, fragmentSelectionSet, variableValues ,
818+ fragmentDeferUsage, depth , visitedFragments)}.
825819 - For each {fragmentGroup} in {fragmentGroupedFieldSet}:
826820 - Let {responseKey} be the response key shared by all fields in
827821 {fragmentGroup}.
828822 - Let {groupForResponseKey} be the list in {groupedFields} for
829823 {responseKey}; if no such list exists, create it as an empty list.
830824 - Append all items in {fragmentGroup} to {groupForResponseKey}.
831- - Append all items in {fragmentNewDeferUsages} to {newDeferUsages}.
832825 - If {selection} is an {InlineFragment}:
833826 - Let {fragmentType} be the type condition on {selection}.
834827 - If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType,
@@ -844,20 +837,19 @@ visitedFragments):
844837 - If {deferDirective} is defined:
845838 - Let {label} be the corresponding entry on {deferDirective}.
846839 - Let {parentDeferUsage} be {deferUsage}.
847- - Let {fragmentDeferUsage} be an unordered map containing {label} and
848- {parentDeferUsage}.
840+ - Let {fragmentDeferUsage} be an unordered map containing {label},
841+ {parentDeferUsage}, and {depth} .
849842 - Otherwise, let {fragmentDeferUsage} be {deferUsage}.
850- - Let {fragmentGroupedFieldSet} and {fragmentNewDeferUsages} be the result
851- of calling {CollectFields(objectType, fragmentSelectionSet,
852- variableValues, fragmentDeferUsage , visitedFragments)}.
843+ - Let {fragmentGroupedFieldSet} be the result of calling
844+ {CollectFields(objectType, fragmentSelectionSet, variableValues ,
845+ fragmentDeferUsage, depth , visitedFragments)}.
853846 - For each {fragmentGroup} in {fragmentGroupedFieldSet}:
854847 - Let {responseKey} be the response key shared by all fields in
855848 {fragmentGroup}.
856849 - Let {groupForResponseKey} be the list in {groupedFields} for
857850 {responseKey}; if no such list exists, create it as an empty list.
858851 - Append all items in {fragmentGroup} to {groupForResponseKey}.
859- - Append all items in {fragmentNewDeferUsages} to {newDeferUsages}.
860- - Return {groupedFields} and {newDeferUsages}.
852+ - Return {groupedFields}.
861853
862854DoesFragmentTypeApply(objectType, fragmentType):
863855
@@ -928,7 +920,7 @@ finally completes that value either by recursively executing another selection
928920set or coercing a scalar value.
929921
930922ExecuteField(objectType, objectValue, fieldType, fieldDetailsList,
931- variableValues, path, deferUsageSet, deferMap ):
923+ variableValues, path, deferUsageSet):
932924
933925- Let {fieldDetails} be the first entry in {fieldDetailsList}.
934926- Let {field} be the corresponding entry on {fieldDetails}.
@@ -939,7 +931,7 @@ variableValues, path, deferUsageSet, deferMap):
939931- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName,
940932 argumentValues)}.
941933- Return the result of {CompleteValue(fieldType, fields, resolvedValue,
942- variableValues, path, deferUsageSet, deferMap )}.
934+ variableValues, path, deferUsageSet)}.
943935
944936### Coercing Field Arguments
945937
@@ -1027,7 +1019,7 @@ the expected return type. If the return type is another Object type, then the
10271019field execution process continues recursively.
10281020
10291021CompleteValue(fieldType, fieldDetailsList, result, variableValues, path,
1030- deferUsageSet, deferMap ):
1022+ deferUsageSet):
10311023
10321024- If the {fieldType} is a Non-Null type:
10331025 - Let {innerType} be the inner type of {fieldType}.
@@ -1041,23 +1033,24 @@ deferUsageSet, deferMap):
10411033 - If {result} is not a collection of values, raise a _ field error_ .
10421034 - Let {innerType} be the inner type of {fieldType}.
10431035 - Return the result of {CompleteListValue(innerType, fieldDetailsList, result,
1044- variableValues, path, deferUsageSet, deferMap )}.
1036+ variableValues, path, deferUsageSet)}.
10451037- If {fieldType} is a Scalar or Enum type:
10461038 - Return the result of {CoerceResult(fieldType, result)}.
10471039- If {fieldType} is an Object, Interface, or Union type:
10481040 - If {fieldType} is an Object type.
10491041 - Let {objectType} be {fieldType}.
10501042 - Otherwise if {fieldType} is an Interface or Union type.
10511043 - Let {objectType} be {ResolveAbstractType(fieldType, result)}.
1052- - Let {groupedFieldSet} and {newDeferUsages} be the result of calling
1053- {CollectSubfields(objectType, fieldDetailsList, variableValues)}.
1044+ - Let {depth} be the length of {path}.
1045+ - Let {groupedFieldSet} be the result of calling {CollectSubfields(objectType,
1046+ fieldDetailsList, variableValues, depth)}.
10541047 - Let {executionPlan} be the result of {BuildExecutionPlan(groupedFieldSet,
10551048 deferUsageSet)}.
1056- - Return the result of {ExecuteExecutionPlan(newDeferUsages, executionPlan ,
1057- objectType, result, variableValues, false, path, deferUsageSet, deferMap )}.
1049+ - Return the result of {ExecuteExecutionPlan(executionPlan, objectType ,
1050+ result, variableValues, false, path, deferUsageSet)}.
10581051
10591052CompleteListValue(innerType, fieldDetailsList, result, variableValues, path,
1060- deferUsageSet, deferMap ):
1053+ deferUsageSet):
10611054
10621055- Initialize {items} and {incrementalDataRecords} to empty lists.
10631056- Let {index} be {0}.
@@ -1136,22 +1129,20 @@ sub-selections.
11361129After resolving the value for ` me ` , the selection sets are merged together so
11371130` firstName ` and ` lastName ` can be resolved for one value.
11381131
1139- CollectSubfields(objectType, fieldDetailsList, variableValues):
1132+ CollectSubfields(objectType, fieldDetailsList, variableValues, depth ):
11401133
11411134- Initialize {groupedFieldSet} to an empty ordered map of lists.
1142- - Initialize {newDeferUsages} to an empty list.
11431135- For each {fieldDetails} in {fieldDetailsList}:
11441136 - Let {field} and {deferUsage} be the corresponding entries on {fieldDetails}.
11451137 - Let {fieldSelectionSet} be the selection set of {field}.
11461138 - If {fieldSelectionSet} is null or empty, continue to the next field.
1147- - Let {subGroupedFieldSet} and {subNewDeferUsages} be the result of
1148- {CollectFields(objectType, fieldSelectionSet, variableValues, deferUsage)}.
1139+ - Let {subGroupedFieldSet} be the result of {CollectFields(objectType,
1140+ fieldSelectionSet, variableValues, deferUsage, depth )}.
11491141 - For each {subGroupedFieldSet} as {responseKey} and {subfields}:
11501142 - Let {groupForResponseKey} be the list in {groupedFieldSet} for
11511143 {responseKey}; if no such list exists, create it as an empty list.
11521144 - Append all fields in {subfields} to {groupForResponseKey}.
1153- - Append all defer usages in {subNewDeferUsages} to {newDeferUsages}.
1154- - Return {groupedFieldSet} and {newDeferUsages}.
1145+ - Return {groupedFieldSet}.
11551146
11561147### Handling Field Errors
11571148
0 commit comments