Skip to content

Commit 5c3f996

Browse files
committed
execution suggestions
1 parent 93d5b0c commit 5c3f996

File tree

1 file changed

+89
-87
lines changed

1 file changed

+89
-87
lines changed

spec/Section 6 -- Execution.md

Lines changed: 89 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,8 @@ CoerceVariableValues(schema, operation, variableValues):
8686
- Let {coercedValues} be an empty unordered Map.
8787
- Let {variablesDefinition} be the variables defined by {operation}.
8888
- For each {variableDefinition} in {variablesDefinition}:
89-
- Let {variableName} be the name of {variableDefinition}.
90-
- Let {variableType} be the expected type of {variableDefinition}.
91-
- Assert: {IsInputType(variableType)} must be {true}.
92-
- Let {defaultValue} be the default value for {variableDefinition}.
89+
- Let {variableName}, {variableType}, and {defaultValue} be the result of
90+
{GetVariableSignature(variableDefinition)}.
9391
- Let {hasValue} be {true} if {variableValues} provides a value for the name
9492
{variableName}.
9593
- Let {value} be the value provided in {variableValues} for the name
@@ -114,6 +112,14 @@ CoerceVariableValues(schema, operation, variableValues):
114112

115113
Note: This algorithm is very similar to {CoerceArgumentValues()}.
116114

115+
GetVariableSignature(variableDefinition):
116+
117+
- Let {variableName} be the name of {variableDefinition}.
118+
- Let {variableType} be the expected type of {variableDefinition}.
119+
- Assert: {IsInputType(variableType)} must be {true}.
120+
- Let {defaultValue} be the default value for {variableDefinition}.
121+
- Return {variableName}, {variableType}, and {defaultValue}.
122+
117123
## Executing Operations
118124

119125
The type system, as described in the "Type System" section of the spec, must
@@ -353,16 +359,16 @@ ExecuteGroupedFieldSet(groupedFieldSet, objectType, objectValue,
353359
variableValues):
354360

355361
- Initialize {resultMap} to an empty ordered map.
356-
- For each {groupedFieldSet} as {responseKey} and {fields}:
357-
- Let {fieldName} be the name of the first entry in {fields}. Note: This value
358-
is unaffected if an alias is used.
359-
- Let {fragmentVariableValues} be the fragment-variables value of the first
360-
entry in {fields}.
362+
- For each {groupedFieldSet} as {responseKey} and {fieldDetailsList}:
363+
- Let {fieldDetails} be the first entry in {fieldDetailsList}.
364+
- Let {field} be the corresponding entry on {fieldDetails}.
365+
- Let {fieldName} be field name of {field}. Note: This value is unaffected if
366+
an alias is used.
361367
- Let {fieldType} be the return type defined for the field {fieldName} of
362368
{objectType}.
363369
- If {fieldType} is defined:
364370
- Let {responseValue} be {ExecuteField(objectType, objectValue, fieldType,
365-
fields, variableValues, fragmentVariableValues)}.
371+
fieldDetailsList, variableValues)}.
366372
- Set {responseValue} as the value for {responseKey} in {resultMap}.
367373
- Return {resultMap}.
368374

@@ -510,46 +516,56 @@ The depth-first-search order of the field groups produced by {CollectFields()}
510516
is maintained through execution, ensuring that fields appear in the executed
511517
response in a stable and predictable order.
512518

513-
CollectFields(objectType, selectionSet, variableValues, visitedFragments,
514-
localVariableValues):
519+
CollectFields(objectType, selectionSet, variableValues, fragmentVariables,
520+
visitedFragments):
515521

516522
- If {visitedFragments} is not provided, initialize it to the empty set.
517523
- Initialize {groupedFields} to an empty ordered map of lists.
518524
- For each {selection} in {selectionSet}:
519525
- If {selection} provides the directive `@skip`, let {skipDirective} be that
520526
directive.
521-
- If {skipDirective}'s {if} argument is {true} or is a variable in
522-
{localVariableValues} or {variableValues} with the value {true}, continue
523-
with the next {selection} in {selectionSet}.
527+
- Let {directiveValues} be the result of {GetDirectiveValues(skipDirective,
528+
variableValues, fragmentVariables)}.
529+
- If the entry for the {if} argument within {directiveValues} is {true},
530+
continue with the next {selection} in {selectionSet}.
524531
- If {selection} provides the directive `@include`, let {includeDirective} be
525532
that directive.
526-
- If {includeDirective}'s {if} argument is not {true} and is not a variable
527-
in {localVariableValues} or {variableValues} with the value {true},
533+
- Let {directiveValues} be the result of
534+
{GetDirectiveValues(includeDirective, variableValues, fragmentVariables)}.
535+
- If the entry for the {if} argument within {directiveValues} is not {true},
528536
continue with the next {selection} in {selectionSet}.
529537
- If {selection} is a {Field}:
530538
- Let {responseKey} be the response key of {selection} (the alias if
531539
defined, otherwise the field name).
532540
- Let {groupForResponseKey} be the list in {groupedFields} for
533541
{responseKey}; if no such list exists, create it as an empty list.
534-
- Append {selection} and {localVariableValues} to the {groupForResponseKey}.
542+
- Let {fieldDetails} be a new unordered map containing {fragmentVariables}.
543+
- Set the entry for {field} on {fieldDetails} to {selection}.
544+
- Append {fieldDetails} to the {groupForResponseKey}.
535545
- If {selection} is a {FragmentSpread}:
536546
- Let {fragmentSpreadName} be the name of {selection}.
547+
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
548+
{selection} in {selectionSet}.
549+
- Add {fragmentSpreadName} to {visitedFragments}.
537550
- Let {fragment} be the Fragment in the current Document whose name is
538551
{fragmentSpreadName}.
539552
- If no such {fragment} exists, continue with the next {selection} in
540553
{selectionSet}.
541-
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
542-
{selection} in {selectionSet}.
543-
- Add {fragmentSpreadName} to {visitedFragments}.
544554
- Let {fragmentType} be the type condition on {fragment}.
545555
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
546556
with the next {selection} in {selectionSet}.
547-
- Let {localVariableValues} be the result of calling
548-
{getArgumentValuesFromSpread(selection, fragmentDefinition,
549-
variableValues, localVariableValues)}.
557+
- Let {variableDefinitions} be the variable definitions for {fragment}.
558+
- Initialize {signatures} to an empty list.
559+
- For each {variableDefinition} of {variableDefinitions}:
560+
- Append the result of {GetVariableSignature(variableDefinition)} to
561+
{signatures}.
562+
- Let {values} be the result of {CoerceArgumentValues(fragment,
563+
argumentDefinitions, variableValues, fragmentVariables)}.
564+
- Let {newFragmentVariables} be an unordered map containing {signatures} and
565+
{values}.
550566
- Let {fragmentGroupedFieldSet} be the result of calling
551567
{CollectFields(objectType, fragmentSelectionSet, variableValues,
552-
visitedFragments)}.
568+
newFragmentVariables, visitedFragments)}.
553569
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
554570
- Let {responseKey} be the response key shared by all fields in
555571
{fragmentGroup}.
@@ -564,7 +580,7 @@ localVariableValues):
564580
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
565581
- Let {fragmentGroupedFieldSet} be the result of calling
566582
{CollectFields(objectType, fragmentSelectionSet, variableValues,
567-
visitedFragments)}.
583+
fragmentVariables, visitedFragments)}.
568584
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
569585
- Let {responseKey} be the response key shared by all fields in
570586
{fragmentGroup}.
@@ -585,32 +601,19 @@ DoesFragmentTypeApply(objectType, fragmentType):
585601
- If {objectType} is a possible type of {fragmentType}, return {true}
586602
otherwise return {false}.
587603

588-
getArgumentValuesFromSpread(fragmentSpread, fragmentDefinition, variableValues,
589-
fragmentArgumentValues):
590-
591-
- Let {coercedValues} be an empty unordered Map.
592-
- For each {variableDefinition} in {fragmentDefinition}:
593-
- Let {variableName} be the name of {variableDefinition}.
594-
- Let {variableType} be the type of {variableDefinition}.
595-
- Let {defaultValue} be the default value for {variableDefinition}.
596-
- Let {argumentNode} be the node provided in the fragment-spread for
597-
{variableName}
598-
- If {argumentNode} isn't present or is null
599-
- If {defaultValue} exists
600-
- Add an entry to {coercedValues} named {argumentName} with the value
601-
{defaultValue}.
602-
- If {variableType} is non-nullable raise a field-error
603-
- Let {hasValue} be {true} if {fragmentArgumentValues} or {variableValues}
604-
provides a value for the name {variableName}.
605-
- If {variableType} is non-nullable and {hasValue} is {false} raise a
606-
field-error
607-
- Add an entry to {coercedValues} named {argumentName} with the value found in
608-
{variableValues} or {fragmentArgumentValues}.
609-
- Return {coercedValues}.
610-
611604
Note: The steps in {CollectFields()} evaluating the `@skip` and `@include`
612605
directives may be applied in either order since they apply commutatively.
613606

607+
GetDirectiveValues(directive, variableValues, fragmentVariables):
608+
609+
- Let {directiveName} be the name of {directive}.
610+
- Let {directiveDefinition} be the definition for {directiveName} within the
611+
schema.
612+
- Assert {directiveDefinition} is defined.
613+
- Let {argumentDefinitions} be the arguments defined by {directiveDefinition}.
614+
- Return the result of {CoerceArgumentValues(directiveDirective,
615+
argumentDefinitions, variableValues, fragmentVariables)}.
616+
614617
## Executing Fields
615618

616619
Each field requested in the grouped field set that is defined on the selected
@@ -619,40 +622,37 @@ coerces any provided argument values, then resolves a value for the field, and
619622
finally completes that value either by recursively executing another selection
620623
set or coercing a scalar value.
621624

622-
ExecuteField(objectType, objectValue, fieldType, fields, variableValues,
623-
fragmentVariableValues):
625+
ExecuteField(objectType, objectValue, fieldType, fieldDetailsList,
626+
variableValues, fragmentVariables):
624627

625-
- Let {field} be the first entry in {fields}.
628+
- Let {fieldDetails} be the first entry in {fieldDetailsList}.
629+
- Let {field} and {fragmentVariables} be the corresponding entries on
630+
{fieldDetails}.
626631
- Let {fieldName} be the field name of {field}.
627-
- Let {argumentValues} be the result of {CoerceFieldArgumentValues(objectType,
628-
field, variableValues, fragmentVariableValues)}
632+
- Let {argumentDefinitions} be the arguments defined by {objectType} for the
633+
field named {fieldName}.
634+
- Let {argumentValues} be the result of {CoerceArgumentValues(field,
635+
argumentDefinitions, variableValues, fragmentVariables)}.
629636
- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName,
630637
argumentValues)}.
631-
- Return the result of {CompleteValue(fieldType, fields, resolvedValue,
632-
variableValues)}.
638+
- Return the result of {CompleteValue(fieldType, fieldDetailsList,
639+
resolvedValue, variableValues)}.
633640

634-
### Coercing Field Arguments
641+
### Coercing Arguments
635642

636-
Fields may include arguments which are provided to the underlying runtime in
637-
order to correctly produce a value. These arguments are defined by the field in
638-
the type system to have a specific input type.
643+
Fields, directives, and fragment spreads may include arguments which are
644+
provided to the underlying runtime in order to correctly produce a value. For
645+
fields and directives, these arguments are defined by the field or directive in
646+
the type system to have a specific input type; for fragment spreads, the
647+
fragment definition within the document specifies the input type.
639648

640649
At each argument position in an operation may be a literal {Value}, or a
641650
{Variable} to be provided at runtime.
642651

643-
CoerceFieldArgumentValues(objectType, field, variableValues,
644-
fragmentVariableValues):
645-
646-
- Let {argumentValues} be the argument values provided in {field}.
647-
- Let {fieldName} be the name of {field}.
648-
- Let {argumentDefinitions} be the arguments defined by {objectType} for the
649-
field named {fieldName}.
650-
- Return {CoerceArgumentValues(argumentDefinitions, argumentValues,
651-
variableValues, fragmentVariableValues)}
652-
653-
CoerceArgumentValues(argumentDefinitions, argumentValues, variableValues,
654-
fragmentVariableValues):
652+
CoerceArgumentValues(node, argumentDefinitions, variableValues,
653+
fragmentVariables):
655654

655+
- Let {argumentValues} be the argument values provided in {node}.
656656
- For each {argumentDefinition} in {argumentDefinitions}:
657657
- Let {argumentName} be the name of {argumentDefinition}.
658658
- Let {argumentType} be the expected type of {argumentDefinition}.
@@ -663,12 +663,12 @@ fragmentVariableValues):
663663
{argumentName}.
664664
- If {argumentValue} is a {Variable}:
665665
- Let {variableName} be the name of {argumentValue}.
666-
- Let {hasValue} be {true} if {fragmentVariableValues} provides a value for
666+
- Let {signatures} and {values} be the corresponding entries on
667+
{fragmentVariables}.
668+
- Let {scopedVariableValues} be {values} if an entry in {signatures} exists
669+
for {variableName}; otherwise, let it be {variableValues}.
670+
- Let {hasValue} be {true} if {scopedVariableValues} provides a value for
667671
the name {variableName}.
668-
- Let {value} be the value provided in {fragmentVariableValues} for the name
669-
{variableName}.
670-
- Let {hasValue} be {true} if {variableValues} provides a value for the name
671-
{variableName}.
672672
- Let {value} be the value provided in {variableValues} for the name
673673
{variableName}.
674674
- Otherwise, let {value} be {argumentValue}.
@@ -726,12 +726,12 @@ After resolving the value for a field, it is completed by ensuring it adheres to
726726
the expected return type. If the return type is another Object type, then the
727727
field execution process continues recursively.
728728

729-
CompleteValue(fieldType, fields, result, variableValues):
729+
CompleteValue(fieldType, fieldDetailsList, result, variableValues):
730730

731731
- If the {fieldType} is a Non-Null type:
732732
- Let {innerType} be the inner type of {fieldType}.
733733
- Let {completedResult} be the result of calling {CompleteValue(innerType,
734-
fields, result, variableValues)}.
734+
fieldDetailsList, result, variableValues)}.
735735
- If {completedResult} is {null}, raise a _field error_.
736736
- Return {completedResult}.
737737
- If {result} is {null} (or another internal value similar to {null} such as
@@ -740,8 +740,8 @@ CompleteValue(fieldType, fields, result, variableValues):
740740
- If {result} is not a collection of values, raise a _field error_.
741741
- Let {innerType} be the inner type of {fieldType}.
742742
- Return a list where each list item is the result of calling
743-
{CompleteValue(innerType, fields, resultItem, variableValues)}, where
744-
{resultItem} is each item in {result}.
743+
{CompleteValue(innerType, fieldDetailsList, resultItem, variableValues)},
744+
where {resultItem} is each item in {result}.
745745
- If {fieldType} is a Scalar or Enum type:
746746
- Return the result of {CoerceResult(fieldType, result)}.
747747
- If {fieldType} is an Object, Interface, or Union type:
@@ -750,7 +750,7 @@ CompleteValue(fieldType, fields, result, variableValues):
750750
- Otherwise if {fieldType} is an Interface or Union type.
751751
- Let {objectType} be {ResolveAbstractType(fieldType, result)}.
752752
- Let {groupedFieldSet} be the result of calling {CollectSubfields(objectType,
753-
fields, variableValues)}.
753+
fieldDetailsList, variableValues)}.
754754
- Return the result of evaluating {ExecuteGroupedFieldSet(groupedFieldSet,
755755
objectType, result, variableValues)} _normally_ (allowing for
756756
parallelization).
@@ -819,18 +819,20 @@ sub-selections.
819819
After resolving the value for `me`, the selection sets are merged together so
820820
`firstName` and `lastName` can be resolved for one value.
821821

822-
CollectSubfields(objectType, fields, variableValues):
822+
CollectSubfields(objectType, fieldDetailsList, variableValues):
823823

824824
- Let {groupedFieldSet} be an empty map.
825-
- For each {field} in {fields}:
825+
- For each {fieldDetails} in {fieldDetailsList}:
826+
- Let {field} be the corresponding entry on {fieldDetails}.
826827
- Let {fieldSelectionSet} be the selection set of {field}.
827828
- If {fieldSelectionSet} is null or empty, continue to the next field.
829+
- Let {fragmentVariables} be the corresponding entry on {fieldDetails}.
828830
- Let {subGroupedFieldSet} be the result of {CollectFields(objectType,
829-
fieldSelectionSet, variableValues)}.
830-
- For each {subGroupedFieldSet} as {responseKey} and {subfields}:
831+
fieldSelectionSet, variableValues, fragmentVariables)}.
832+
- For each {subGroupedFieldSet} as {responseKey} and {subfieldDetailsList}:
831833
- Let {groupForResponseKey} be the list in {groupedFieldSet} for
832834
{responseKey}; if no such list exists, create it as an empty list.
833-
- Append all fields in {subfields} to {groupForResponseKey}.
835+
- Append all fields in {subfieldDetailsList} to {groupForResponseKey}.
834836
- Return {groupedFieldSet}.
835837

836838
### Handling Field Errors

0 commit comments

Comments
 (0)