Skip to content

Commit 8c4e68b

Browse files
committed
Fixes
1 parent 1bc46cf commit 8c4e68b

File tree

2 files changed

+26
-137
lines changed

2 files changed

+26
-137
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: 17 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,8 @@ The depth-first-search order of the _field set_ produced by {CollectFields()} is
446446
maintained through execution, ensuring that fields appear in the executed
447447
response in a stable and predictable order.
448448

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

451452
- If {visitedFragments} is not provided, initialize it to the empty set.
452453
- Initialize {collectedFieldsMap} to an empty ordered map of ordered sets.
@@ -464,10 +465,12 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
464465
- If {selection} is a {Field}:
465466
- Let {responseName} be the _response name_ of {selection} (the alias if
466467
defined, otherwise the field name).
467-
- Let {fieldsForResponseName} be the _field set_ value in
468+
- Let {fieldsForResponseName} be the _field map_ value in
468469
{collectedFieldsMap} for the key {responseName}; otherwise create the
469470
entry with an empty ordered set.
470-
- Add {selection} to the {fieldsForResponseName}.
471+
- Let {fieldDetails} be a new unordered map containing {fragmentVariables}.
472+
- Set the entry for {field} on {fieldDetails} to {selection}.
473+
- Add {fieldDetails} to the {fieldsForResponseName}.
471474
- If {selection} is a {FragmentSpread}:
472475
- Let {fragmentSpreadName} be the name of {selection}.
473476
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
@@ -480,10 +483,19 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
480483
- Let {fragmentType} be the type condition on {fragment}.
481484
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
482485
with the next {selection} in {selectionSet}.
486+
- Let {variableDefinitions} be the variable definitions for {fragment}.
487+
- Initialize {signatures} to an empty list.
488+
- For each {variableDefinition} of {variableDefinitions}:
489+
- Append the result of {GetVariableSignature(variableDefinition)} to
490+
{signatures}.
491+
- Let {values} be the result of {CoerceArgumentValues(fragment,
492+
argumentDefinitions, variableValues, fragmentVariables)}.
493+
- Let {newFragmentVariables} be an unordered map containing {signatures} and
494+
{values}.
483495
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
484496
- Let {fragmentCollectedFieldMap} be the result of calling
485497
{CollectFields(objectType, fragmentSelectionSet, variableValues,
486-
visitedFragments)}.
498+
visitedFragments, newFragmentVariables)}.
487499
- For each {responseName} and {fragmentFields} in
488500
{fragmentCollectedFieldMap}:
489501
- Let {fieldsForResponseName} be the _field set_ value in
@@ -498,7 +510,7 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
498510
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
499511
- Let {fragmentCollectedFieldMap} be the result of calling
500512
{CollectFields(objectType, fragmentSelectionSet, variableValues,
501-
visitedFragments)}.
513+
visitedFragments, fragmentVariables)}.
502514
- For each {responseName} and {fragmentFields} in
503515
{fragmentCollectedFieldMap}:
504516
- Let {fieldsForResponseName} be the _field set_ value in
@@ -720,134 +732,6 @@ A correct executor must generate the following result for that _selection set_:
720732
}
721733
```
722734

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-
851735
## Executing Fields
852736

853737
Each entry in a result map is the result of executing a field on an object type

0 commit comments

Comments
 (0)