Skip to content

Commit 0ffed63

Browse files
committed
moves Field Collection section earlier
1 parent 3488636 commit 0ffed63

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
@@ -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
@@ -474,112 +580,6 @@ A correct executor must generate the following result for that _selection set_:
474580
}
475581
```
476582

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

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

0 commit comments

Comments
 (0)