Skip to content

Commit 60a9c35

Browse files
authored
move Field Collection section earlier (#1111)
1 parent a52310e commit 60a9c35

File tree

1 file changed

+106
-106
lines changed

1 file changed

+106
-106
lines changed

spec/Section 6 -- Execution.md

Lines changed: 106 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,112 @@ serial):
340340
selection set.
341341
- Return an unordered map containing {data} and {errors}.
342342

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

345451
To execute a grouped field set, the object value being evaluated and the object
@@ -477,112 +583,6 @@ A correct executor must generate the following result for that _selection set_:
477583
}
478584
```
479585

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

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

0 commit comments

Comments
 (0)