Skip to content

Commit cbf902b

Browse files
committed
Fixes
1 parent 1bc46cf commit cbf902b

File tree

2 files changed

+46
-160
lines changed

2 files changed

+46
-160
lines changed

spec/Section 5 -- Validation.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -532,12 +532,17 @@ fragment directFieldSelectionOnUnion on CatOrDog {
532532
- Let {set} be any selection set defined in the GraphQL document.
533533
- {FieldsInSetCanMerge(set)} must be true.
534534

535-
#### TODO: problematic part, this used to allow us to look at fragmentspread
536-
537535
FieldsInSetCanMerge(set):
538536

539-
- Let {fieldsForName} be the set of selections with a given _response name_ in
540-
{set} including visiting fragments and inline fragments.
537+
- Let {visitedSelections} be the selections in {set} including visiting fields,
538+
fragment-spreads and inline fragments.
539+
- Let {spreadsForName} be the set of fragment spreads with a given name in
540+
{visitedSelections}.
541+
- For each {spreadsForName} as {name} and {spreads}:
542+
- Each entry in {spreads} must have identical sets of arguments to each other
543+
entry in {spreads}.
544+
- Let {fieldsForName} be the set of field selections with a given response name
545+
in {visitedSelections}.
541546
- Given each pair of distinct members {fieldA} and {fieldB} in {fieldsForName}:
542547
- {SameResponseShape(fieldA, fieldB)} must be true.
543548
- If the parent types of {fieldA} and {fieldB} are equal or if either is not

spec/Section 6 -- Execution.md

Lines changed: 37 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ CreateSourceEventStream(subscription, schema, variableValues, initialValue):
286286
selectionSet, variableValues)}.
287287
- If {collectedFieldsMap} does not have exactly one entry, raise a _request
288288
error_.
289-
- Let {fields} be the value of the first entry in {collectedFieldsMap}.
290-
- Let {fieldName} be the name of the first entry in {fields}. Note: This value
289+
- Let {fieldInfo} be the value of the first entry in {collectedFieldsMap}.
290+
- Let {field} be the value of the {field} property in {fieldInfo}.
291+
- Let {fieldName} be the name of the first entry in {fields}' {field} property. Note: This value
291292
is unaffected if an alias is used.
292293
- Let {field} be the first entry in {fields}.
293294
- Let {argumentValues} be the result of {CoerceArgumentValues(subscriptionType,
@@ -446,7 +447,8 @@ The depth-first-search order of the _field set_ produced by {CollectFields()} is
446447
maintained through execution, ensuring that fields appear in the executed
447448
response in a stable and predictable order.
448449

449-
CollectFields(objectType, selectionSet, variableValues, visitedFragments):
450+
CollectFields(objectType, selectionSet, variableValues, visitedFragments,
451+
fragmentVariables):
450452

451453
- If {visitedFragments} is not provided, initialize it to the empty set.
452454
- Initialize {collectedFieldsMap} to an empty ordered map of ordered sets.
@@ -467,7 +469,9 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
467469
- Let {fieldsForResponseName} be the _field set_ value in
468470
{collectedFieldsMap} for the key {responseName}; otherwise create the
469471
entry with an empty ordered set.
470-
- Add {selection} to the {fieldsForResponseName}.
472+
- Let {fieldDetails} be a new unordered map containing {fragmentVariables}.
473+
- Set the entry for {field} on {fieldDetails} to {selection}.
474+
- Add {fieldDetails} to the {fieldsForResponseName}.
471475
- If {selection} is a {FragmentSpread}:
472476
- Let {fragmentSpreadName} be the name of {selection}.
473477
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
@@ -480,10 +484,19 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
480484
- Let {fragmentType} be the type condition on {fragment}.
481485
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
482486
with the next {selection} in {selectionSet}.
487+
- Let {variableDefinitions} be the variable definitions for {fragment}.
488+
- Initialize {signatures} to an empty list.
489+
- For each {variableDefinition} of {variableDefinitions}:
490+
- Append the result of {GetVariableSignature(variableDefinition)} to
491+
{signatures}.
492+
- Let {values} be the result of {CoerceArgumentValues(fragment,
493+
argumentDefinitions, variableValues, fragmentVariables)}.
494+
- Let {newFragmentVariables} be an unordered map containing {signatures} and
495+
{values}.
483496
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
484497
- Let {fragmentCollectedFieldMap} be the result of calling
485498
{CollectFields(objectType, fragmentSelectionSet, variableValues,
486-
visitedFragments)}.
499+
visitedFragments, newFragmentVariables)}.
487500
- For each {responseName} and {fragmentFields} in
488501
{fragmentCollectedFieldMap}:
489502
- Let {fieldsForResponseName} be the _field set_ value in
@@ -498,7 +511,7 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
498511
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
499512
- Let {fragmentCollectedFieldMap} be the result of calling
500513
{CollectFields(objectType, fragmentSelectionSet, variableValues,
501-
visitedFragments)}.
514+
visitedFragments, fragmentVariables)}.
502515
- For each {responseName} and {fragmentFields} in
503516
{fragmentCollectedFieldMap}:
504517
- Let {fieldsForResponseName} be the _field set_ value in
@@ -562,11 +575,11 @@ CollectSubfields(objectType, fields, variableValues):
562575
- If {fieldSelectionSet} is null or empty, continue to the next field.
563576
- Let {fieldCollectedFieldMap} be the result of {CollectFields(objectType,
564577
fieldSelectionSet, variableValues)}.
565-
- For each {responseName} and {subfields} in {fieldCollectedFieldMap}:
578+
- For each {responseName} and {subfieldInfos} in {fieldCollectedFieldMap}:
566579
- Let {fieldsForResponseName} be the _field set_ value in
567580
{collectedFieldsMap} for the key {responseName}; otherwise create the
568581
entry with an empty ordered set.
569-
- Add each fields from {subfields} to {fieldsForResponseName}.
582+
- Add each fieldInfo from {subfields} to {fieldsForResponseName}.
570583
- Return {collectedFieldsMap}.
571584

572585
Note: All the {fields} passed to {CollectSubfields()} share the same _response
@@ -585,11 +598,12 @@ ExecuteCollectedFields(collectedFieldsMap, objectType, objectValue,
585598
variableValues):
586599

587600
- Initialize {resultMap} to an empty ordered map.
588-
- For each {responseName} and {fields} in {collectedFieldsMap}:
601+
- For each {responseName} and {fieldInfos} in {collectedFieldsMap}:
602+
- Let {fieldInfo} be the first entry in {fieldInfos}.
603+
- Let {field} be the field property of {fieldInfo}.
589604
- Let {fieldName} be the name of the first entry in {fields}. Note: This value
590605
is unaffected if an alias is used.
591-
- Let {fragmentVariableValues} be the fragment-variables value of the first
592-
entry in {fields}.
606+
- Let {fragmentVariableValues} be the fragmentVariables property of {fieldInfo}.
593607
- Let {fieldType} be the return type defined for the field {fieldName} of
594608
{objectType}.
595609
- If {fieldType} is defined:
@@ -720,134 +734,6 @@ A correct executor must generate the following result for that _selection set_:
720734
}
721735
```
722736

723-
### Field Collection
724-
725-
Before execution, the _selection set_ is converted to a grouped field set by
726-
calling {CollectFields()}. Each entry in the grouped field set is a list of
727-
fields that share a response key (the alias if defined, otherwise the field
728-
name). This ensures all fields with the same response key (including those in
729-
referenced fragments) are executed at the same time.
730-
731-
As an example, collecting the fields of this selection set would collect two
732-
instances of the field `a` and one of field `b`:
733-
734-
```graphql example
735-
{
736-
a {
737-
subfield1
738-
}
739-
...ExampleFragment
740-
}
741-
742-
fragment ExampleFragment on Query {
743-
a {
744-
subfield2
745-
}
746-
b
747-
}
748-
```
749-
750-
The depth-first-search order of the field groups produced by {CollectFields()}
751-
is maintained through execution, ensuring that fields appear in the executed
752-
response in a stable and predictable order.
753-
754-
CollectFields(objectType, selectionSet, variableValues, visitedFragments,
755-
fragmentVariables):
756-
757-
- If {visitedFragments} is not provided, initialize it to the empty set.
758-
- Initialize {groupedFields} to an empty ordered map of lists.
759-
- For each {selection} in {selectionSet}:
760-
- If {selection} provides the directive `@skip`, let {skipDirective} be that
761-
directive.
762-
- Let {directiveValues} be the result of {GetDirectiveValues(skipDirective,
763-
variableValues, fragmentVariables)}.
764-
- If the entry for the {if} argument within {directiveValues} is {true},
765-
continue with the next {selection} in {selectionSet}.
766-
- If {selection} provides the directive `@include`, let {includeDirective} be
767-
that directive.
768-
- Let {directiveValues} be the result of
769-
{GetDirectiveValues(includeDirective, variableValues, fragmentVariables)}.
770-
- If the entry for the {if} argument within {directiveValues} is not {true},
771-
- If {selection} is a {Field}:
772-
- Let {responseKey} be the response key of {selection} (the alias if
773-
defined, otherwise the field name).
774-
- Let {groupForResponseKey} be the list in {groupedFields} for
775-
{responseKey}; if no such list exists, create it as an empty list.
776-
- Let {fieldDetails} be a new unordered map containing {fragmentVariables}.
777-
- Set the entry for {field} on {fieldDetails} to {selection}.
778-
- Append {fieldDetails} to the {groupForResponseKey}.
779-
- If {selection} is a {FragmentSpread}:
780-
- Let {fragmentSpreadName} be the name of {selection}.
781-
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
782-
{selection} in {selectionSet}.
783-
- Add {fragmentSpreadName} to {visitedFragments}.
784-
- Let {fragment} be the Fragment in the current Document whose name is
785-
{fragmentSpreadName}.
786-
- If no such {fragment} exists, continue with the next {selection} in
787-
{selectionSet}.
788-
- Let {fragmentType} be the type condition on {fragment}.
789-
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
790-
with the next {selection} in {selectionSet}.
791-
- Let {variableDefinitions} be the variable definitions for {fragment}.
792-
- Initialize {signatures} to an empty list.
793-
- For each {variableDefinition} of {variableDefinitions}:
794-
- Append the result of {GetVariableSignature(variableDefinition)} to
795-
{signatures}.
796-
- Let {values} be the result of {CoerceArgumentValues(fragment,
797-
argumentDefinitions, variableValues, fragmentVariables)}.
798-
- Let {newFragmentVariables} be an unordered map containing {signatures} and
799-
{values}.
800-
- Let {fragmentGroupedFieldSet} be the result of calling
801-
{CollectFields(objectType, fragmentSelectionSet, variableValues,
802-
visitedFragments, newFragmentVariables)}.
803-
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
804-
- Let {responseKey} be the response key shared by all fields in
805-
{fragmentGroup}.
806-
- Let {groupForResponseKey} be the list in {groupedFields} for
807-
{responseKey}; if no such list exists, create it as an empty list.
808-
- Append all items in {fragmentGroup} to {groupForResponseKey}.
809-
- If {selection} is an {InlineFragment}:
810-
- Let {fragmentType} be the type condition on {selection}.
811-
- If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType,
812-
fragmentType)} is {false}, continue with the next {selection} in
813-
{selectionSet}.
814-
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
815-
- Let {fragmentGroupedFieldSet} be the result of calling
816-
{CollectFields(objectType, fragmentSelectionSet, variableValues,
817-
visitedFragments, fragmentVariables)}.
818-
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
819-
- Let {responseKey} be the response key shared by all fields in
820-
{fragmentGroup}.
821-
- Let {groupForResponseKey} be the list in {groupedFields} for
822-
{responseKey}; if no such list exists, create it as an empty list.
823-
- Append all items in {fragmentGroup} to {groupForResponseKey}.
824-
- Return {groupedFields}.
825-
826-
DoesFragmentTypeApply(objectType, fragmentType):
827-
828-
- If {fragmentType} is an Object Type:
829-
- If {objectType} and {fragmentType} are the same type, return {true},
830-
otherwise return {false}.
831-
- If {fragmentType} is an Interface Type:
832-
- If {objectType} is an implementation of {fragmentType}, return {true}
833-
otherwise return {false}.
834-
- If {fragmentType} is a Union:
835-
- If {objectType} is a possible type of {fragmentType}, return {true}
836-
otherwise return {false}.
837-
838-
Note: The steps in {CollectFields()} evaluating the `@skip` and `@include`
839-
directives may be applied in either order since they apply commutatively.
840-
841-
GetDirectiveValues(directive, variableValues, fragmentVariables):
842-
843-
- Let {directiveName} be the name of {directive}.
844-
- Let {directiveDefinition} be the definition for {directiveName} within the
845-
schema.
846-
- Assert {directiveDefinition} is defined.
847-
- Let {argumentDefinitions} be the arguments defined by {directiveDefinition}.
848-
- Return the result of {CoerceArgumentValues(directiveDefinition,
849-
argumentDefinitions, variableValues, fragmentVariables)}.
850-
851737
## Executing Fields
852738

853739
Each entry in a result map is the result of executing a field on an object type
@@ -856,19 +742,16 @@ first coerces any provided argument values, then resolves a value for the field,
856742
and finally completes that value either by recursively executing another
857743
selection set or coercing a scalar value.
858744

859-
### TODO: this needs updating
860-
861-
ExecuteField(objectType, objectValue, fieldType, fields, variableValues,
862-
fragmentVariableValues):
745+
ExecuteField(objectType, objectValue, fieldType, fieldDetailsList, variableValues,
746+
fragmentVariables):
863747

864-
- Let {field} be the first entry in {fields}.
748+
- Let {fieldDetails} be the first entry in {fieldDetailsList}.
749+
- Let {field} and {fragmentVariables} be the corresponding entries on {fieldDetails}.
865750
- Let {fieldName} be the field name of {field}.
866-
- Let {argumentValues} be the result of {CoerceFieldArgumentValues(objectType,
867-
field, variableValues, fragmentVariableValues)}
868-
- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName,
869-
argumentValues)}.
870-
- Return the result of {CompleteValue(fieldType, fields, resolvedValue,
871-
variableValues)}.
751+
- Let {argumentDefinitions} be the arguments defined by {objectType} for the field named {fieldName}.
752+
- Let {argumentValues} be the result of {CoerceArgumentValues(field, argumentDefinitions, variableValues, fragmentVariables)}.
753+
- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName, argumentValues)}.
754+
Return the result of {CompleteValue(fieldType, fieldDetailsList, resolvedValue, variableValues)}.
872755

873756
### Coercing Arguments
874757

@@ -977,14 +860,12 @@ the expected return type. If the return type is another Object type, then the
977860
field execution process continues recursively by collecting and executing
978861
subfields.
979862

980-
### TODO: needs updating with fieldDetails
981-
982-
CompleteValue(fieldType, fields, result, variableValues):
863+
CompleteValue(fieldType, fieldDetailsList, result, variableValues):
983864

984865
- If the {fieldType} is a Non-Null type:
985866
- Let {innerType} be the inner type of {fieldType}.
986867
- Let {completedResult} be the result of calling {CompleteValue(innerType,
987-
fields, result, variableValues)}.
868+
fieldDetailsList, result, variableValues)}.
988869
- If {completedResult} is {null}, raise an _execution error_.
989870
- Return {completedResult}.
990871
- If {result} is {null} (or another internal value similar to {null} such as
@@ -993,7 +874,7 @@ CompleteValue(fieldType, fields, result, variableValues):
993874
- If {result} is not a collection of values, raise an _execution error_.
994875
- Let {innerType} be the inner type of {fieldType}.
995876
- Return a list where each list item is the result of calling
996-
{CompleteValue(innerType, fields, resultItem, variableValues)}, where
877+
{CompleteValue(innerType, fieldDetailsList, resultItem, variableValues)}, where
997878
{resultItem} is each item in {result}.
998879
- If {fieldType} is a Scalar or Enum type:
999880
- Return the result of {CoerceResult(fieldType, result)}.
@@ -1003,7 +884,7 @@ CompleteValue(fieldType, fields, result, variableValues):
1003884
- Otherwise if {fieldType} is an Interface or Union type.
1004885
- Let {objectType} be {ResolveAbstractType(fieldType, result)}.
1005886
- Let {collectedFieldsMap} be the result of calling
1006-
{CollectSubfields(objectType, fields, variableValues)}.
887+
{CollectSubfields(objectType, fieldDetailsList, variableValues)}.
1007888
- Return the result of evaluating {ExecuteCollectedFields(collectedFieldsMap,
1008889
objectType, result, variableValues)} _normally_ (allowing for
1009890
parallelization).

0 commit comments

Comments
 (0)