Skip to content

Commit 61bad40

Browse files
committed
moves Field Collection section earlier
1 parent 145c560 commit 61bad40

File tree

1 file changed

+106
-106
lines changed

1 file changed

+106
-106
lines changed

spec/Section 6 -- Execution.md

+106-106
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,112 @@ serial):
336336
selection set.
337337
- Return an unordered map containing {data} and {errors}.
338338

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

341447
To execute a grouped field set, the object value being evaluated and the object
@@ -471,112 +577,6 @@ A correct executor must generate the following result for that selection set:
471577
}
472578
```
473579

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

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

0 commit comments

Comments
 (0)