Skip to content

Commit 8fd0df3

Browse files
committed
move Field Collection section earlier
as it is used during ExecuteRootSelectionSet
1 parent 4d62b8b commit 8fd0df3

File tree

1 file changed

+107
-107
lines changed

1 file changed

+107
-107
lines changed

spec/Section 6 -- Execution.md

Lines changed: 107 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,112 @@ serial):
337337
selection set.
338338
- Return an unordered map containing {data} and {errors}.
339339

340+
### Field Collection
341+
342+
Before execution, the selection set is converted to a grouped field set by
343+
calling {CollectFields()}. Each entry in the grouped field set is a list of
344+
fields that share a response key (the alias if defined, otherwise the field
345+
name). This ensures all fields with the same response key (including those in
346+
referenced fragments) are executed at the same time.
347+
348+
As an example, collecting the fields of this selection set would collect two
349+
instances of the field `a` and one of field `b`:
350+
351+
```graphql example
352+
{
353+
a {
354+
subfield1
355+
}
356+
...ExampleFragment
357+
}
358+
359+
fragment ExampleFragment on Query {
360+
a {
361+
subfield2
362+
}
363+
b
364+
}
365+
```
366+
367+
The depth-first-search order of the field groups produced by {CollectFields()}
368+
is maintained through execution, ensuring that fields appear in the executed
369+
response in a stable and predictable order.
370+
371+
CollectFields(objectType, selectionSet, variableValues, visitedFragments):
372+
373+
- If {visitedFragments} is not provided, initialize it to the empty set.
374+
- Initialize {groupedFields} to an empty ordered map of lists.
375+
- For each {selection} in {selectionSet}:
376+
- If {selection} provides the directive `@skip`, let {skipDirective} be that
377+
directive.
378+
- If {skipDirective}'s {if} argument is {true} or is a variable in
379+
{variableValues} with the value {true}, continue with the next {selection}
380+
in {selectionSet}.
381+
- If {selection} provides the directive `@include`, let {includeDirective} be
382+
that directive.
383+
- If {includeDirective}'s {if} argument is not {true} and is not a variable
384+
in {variableValues} with the value {true}, continue with the next
385+
{selection} in {selectionSet}.
386+
- If {selection} is a {Field}:
387+
- Let {responseKey} be the response key of {selection} (the alias if
388+
defined, otherwise the field name).
389+
- Let {groupForResponseKey} be the list in {groupedFields} for
390+
{responseKey}; if no such list exists, create it as an empty list.
391+
- Append {selection} to the {groupForResponseKey}.
392+
- If {selection} is a {FragmentSpread}:
393+
- Let {fragmentSpreadName} be the name of {selection}.
394+
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
395+
{selection} in {selectionSet}.
396+
- Add {fragmentSpreadName} to {visitedFragments}.
397+
- Let {fragment} be the Fragment in the current Document whose name is
398+
{fragmentSpreadName}.
399+
- If no such {fragment} exists, continue with the next {selection} in
400+
{selectionSet}.
401+
- Let {fragmentType} be the type condition on {fragment}.
402+
- If {DoesFragmentTypeApply(objectType, fragmentType)} is false, continue
403+
with the next {selection} in {selectionSet}.
404+
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
405+
- Let {fragmentGroupedFieldSet} be the result of calling
406+
{CollectFields(objectType, fragmentSelectionSet, variableValues,
407+
visitedFragments)}.
408+
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
409+
- Let {responseKey} be the response key shared by all fields in
410+
{fragmentGroup}.
411+
- Let {groupForResponseKey} be the list in {groupedFields} for
412+
{responseKey}; if no such list exists, create it as an empty list.
413+
- Append all items in {fragmentGroup} to {groupForResponseKey}.
414+
- If {selection} is an {InlineFragment}:
415+
- Let {fragmentType} be the type condition on {selection}.
416+
- If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType,
417+
fragmentType)} is false, continue with the next {selection} in
418+
{selectionSet}.
419+
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
420+
- Let {fragmentGroupedFieldSet} be the result of calling
421+
{CollectFields(objectType, fragmentSelectionSet, variableValues,
422+
visitedFragments)}.
423+
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
424+
- Let {responseKey} be the response key shared by all fields in
425+
{fragmentGroup}.
426+
- Let {groupForResponseKey} be the list in {groupedFields} for
427+
{responseKey}; if no such list exists, create it as an empty list.
428+
- Append all items in {fragmentGroup} to {groupForResponseKey}.
429+
- Return {groupedFields}.
430+
431+
DoesFragmentTypeApply(objectType, fragmentType):
432+
433+
- If {fragmentType} is an Object Type:
434+
- if {objectType} and {fragmentType} are the same type, return {true},
435+
otherwise return {false}.
436+
- If {fragmentType} is an Interface Type:
437+
- if {objectType} is an implementation of {fragmentType}, return {true}
438+
otherwise return {false}.
439+
- If {fragmentType} is a Union:
440+
- if {objectType} is a possible type of {fragmentType}, return {true}
441+
otherwise return {false}.
442+
443+
Note: The steps in {CollectFields()} evaluating the `@skip` and `@include`
444+
directives may be applied in either order since they apply commutatively.
445+
340446
## Executing a Grouped Field Set
341447

342448
To execute a grouped field set, the object value being evaluated and the object
@@ -362,7 +468,7 @@ variableValues):
362468
- Return {resultMap}.
363469

364470
Note: {resultMap} is ordered by which fields appear first in the operation. This
365-
is explained in greater detail in the Field Collection section below.
471+
is explained in greater detail in the Field Collection section above.
366472

367473
**Errors and Non-Null Fields**
368474

@@ -472,112 +578,6 @@ A correct executor must generate the following result for that selection set:
472578
}
473579
```
474580

475-
### Field Collection
476-
477-
Before execution, the selection set is converted to a grouped field set by
478-
calling {CollectFields()}. Each entry in the grouped field set is a list of
479-
fields that share a response key (the alias if defined, otherwise the field
480-
name). This ensures all fields with the same response key (including those in
481-
referenced fragments) are executed at the same time.
482-
483-
As an example, collecting the fields of this selection set would collect two
484-
instances of the field `a` and one of field `b`:
485-
486-
```graphql example
487-
{
488-
a {
489-
subfield1
490-
}
491-
...ExampleFragment
492-
}
493-
494-
fragment ExampleFragment on Query {
495-
a {
496-
subfield2
497-
}
498-
b
499-
}
500-
```
501-
502-
The depth-first-search order of the field groups produced by {CollectFields()}
503-
is maintained through execution, ensuring that fields appear in the executed
504-
response in a stable and predictable order.
505-
506-
CollectFields(objectType, selectionSet, variableValues, visitedFragments):
507-
508-
- If {visitedFragments} is not provided, initialize it to the empty set.
509-
- Initialize {groupedFields} to an empty ordered map of lists.
510-
- For each {selection} in {selectionSet}:
511-
- If {selection} provides the directive `@skip`, let {skipDirective} be that
512-
directive.
513-
- If {skipDirective}'s {if} argument is {true} or is a variable in
514-
{variableValues} with the value {true}, continue with the next {selection}
515-
in {selectionSet}.
516-
- If {selection} provides the directive `@include`, let {includeDirective} be
517-
that directive.
518-
- If {includeDirective}'s {if} argument is not {true} and is not a variable
519-
in {variableValues} with the value {true}, continue with the next
520-
{selection} in {selectionSet}.
521-
- If {selection} is a {Field}:
522-
- Let {responseKey} be the response key of {selection} (the alias if
523-
defined, otherwise the field name).
524-
- Let {groupForResponseKey} be the list in {groupedFields} for
525-
{responseKey}; if no such list exists, create it as an empty list.
526-
- Append {selection} to the {groupForResponseKey}.
527-
- If {selection} is a {FragmentSpread}:
528-
- Let {fragmentSpreadName} be the name of {selection}.
529-
- If {fragmentSpreadName} is in {visitedFragments}, continue with the next
530-
{selection} in {selectionSet}.
531-
- Add {fragmentSpreadName} to {visitedFragments}.
532-
- Let {fragment} be the Fragment in the current Document whose name is
533-
{fragmentSpreadName}.
534-
- If no such {fragment} exists, continue with the next {selection} in
535-
{selectionSet}.
536-
- Let {fragmentType} be the type condition on {fragment}.
537-
- If {DoesFragmentTypeApply(objectType, fragmentType)} is false, continue
538-
with the next {selection} in {selectionSet}.
539-
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
540-
- Let {fragmentGroupedFieldSet} be the result of calling
541-
{CollectFields(objectType, fragmentSelectionSet, variableValues,
542-
visitedFragments)}.
543-
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
544-
- Let {responseKey} be the response key shared by all fields in
545-
{fragmentGroup}.
546-
- Let {groupForResponseKey} be the list in {groupedFields} for
547-
{responseKey}; if no such list exists, create it as an empty list.
548-
- Append all items in {fragmentGroup} to {groupForResponseKey}.
549-
- If {selection} is an {InlineFragment}:
550-
- Let {fragmentType} be the type condition on {selection}.
551-
- If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType,
552-
fragmentType)} is false, continue with the next {selection} in
553-
{selectionSet}.
554-
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
555-
- Let {fragmentGroupedFieldSet} be the result of calling
556-
{CollectFields(objectType, fragmentSelectionSet, variableValues,
557-
visitedFragments)}.
558-
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
559-
- Let {responseKey} be the response key shared by all fields in
560-
{fragmentGroup}.
561-
- Let {groupForResponseKey} be the list in {groupedFields} for
562-
{responseKey}; if no such list exists, create it as an empty list.
563-
- Append all items in {fragmentGroup} to {groupForResponseKey}.
564-
- Return {groupedFields}.
565-
566-
DoesFragmentTypeApply(objectType, fragmentType):
567-
568-
- If {fragmentType} is an Object Type:
569-
- if {objectType} and {fragmentType} are the same type, return {true},
570-
otherwise return {false}.
571-
- If {fragmentType} is an Interface Type:
572-
- if {objectType} is an implementation of {fragmentType}, return {true}
573-
otherwise return {false}.
574-
- If {fragmentType} is a Union:
575-
- if {objectType} is a possible type of {fragmentType}, return {true}
576-
otherwise return {false}.
577-
578-
Note: The steps in {CollectFields()} evaluating the `@skip` and `@include`
579-
directives may be applied in either order since they apply commutatively.
580-
581581
## Executing Fields
582582

583583
Each field requested in the grouped field set that is defined on the selected

0 commit comments

Comments
 (0)