From 700992e3f4a22ac2634c4af771ca8b96b7cfb836 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 12:14:54 +0100 Subject: [PATCH 1/8] Resolve ambiguity - we mean return type For `type User { name: String }`, `User.name` is a field of an object type (`User`). Clarify that we mean the return type of the field, not the type to which it belongs. --- spec/Section 3 -- Type System.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 79953a4e0..95a905ce8 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -775,8 +775,8 @@ type Person { } ``` -Valid operations must supply a _selection set_ for every field of an object -type, so this operation is not valid: +Valid operations must supply a _selection set_ for every field whose return type +is an object type, so this operation is not valid: ```graphql counter-example { From c717d5ea6d5b4f8581a01381bf663c8781e8ed30 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 12:17:20 +0100 Subject: [PATCH 2/8] Consistency with collectedFieldsMap --- spec/Section 5 -- Validation.md | 8 ++++---- spec/Section 6 -- Execution.md | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 206814d6d..982b9b3ad 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -334,11 +334,11 @@ CollectSubscriptionFields(objectType, selectionSet, visitedFragments): - If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue with the next {selection} in {selectionSet}. - Let {fragmentSelectionSet} be the top-level selection set of {fragment}. - - Let {fragmentCollectedFieldMap} be the result of calling + - Let {fragmentCollectedFieldsMap} be the result of calling {CollectSubscriptionFields(objectType, fragmentSelectionSet, visitedFragments)}. - For each {responseName} and {fragmentFields} in - {fragmentCollectedFieldMap}: + {fragmentCollectedFieldsMap}: - Let {fieldsForResponseKey} be the _field set_ value in {collectedFieldsMap} for the key {responseName}; otherwise create the entry with an empty ordered set. @@ -349,11 +349,11 @@ CollectSubscriptionFields(objectType, selectionSet, visitedFragments): fragmentType)} is {false}, continue with the next {selection} in {selectionSet}. - Let {fragmentSelectionSet} be the top-level selection set of {selection}. - - Let {fragmentCollectedFieldMap} be the result of calling + - Let {fragmentCollectedFieldsMap} be the result of calling {CollectSubscriptionFields(objectType, fragmentSelectionSet, visitedFragments)}. - For each {responseName} and {fragmentFields} in - {fragmentCollectedFieldMap}: + {fragmentCollectedFieldsMap}: - Let {fieldsForResponseKey} be the _field set_ value in {collectedFieldsMap} for the key {responseName}; otherwise create the entry with an empty ordered set. diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index b2c533bb3..dc64446a2 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -475,11 +475,11 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments): - If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue with the next {selection} in {selectionSet}. - Let {fragmentSelectionSet} be the top-level selection set of {fragment}. - - Let {fragmentCollectedFieldMap} be the result of calling + - Let {fragmentCollectedFieldsMap} be the result of calling {CollectFields(objectType, fragmentSelectionSet, variableValues, visitedFragments)}. - For each {responseName} and {fragmentFields} in - {fragmentCollectedFieldMap}: + {fragmentCollectedFieldsMap}: - Let {fieldsForResponseName} be the _field set_ value in {collectedFieldsMap} for the key {responseName}; otherwise create the entry with an empty ordered set. @@ -490,11 +490,11 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments): fragmentType)} is {false}, continue with the next {selection} in {selectionSet}. - Let {fragmentSelectionSet} be the top-level selection set of {selection}. - - Let {fragmentCollectedFieldMap} be the result of calling + - Let {fragmentCollectedFieldsMap} be the result of calling {CollectFields(objectType, fragmentSelectionSet, variableValues, visitedFragments)}. - For each {responseName} and {fragmentFields} in - {fragmentCollectedFieldMap}: + {fragmentCollectedFieldsMap}: - Let {fieldsForResponseName} be the _field set_ value in {collectedFieldsMap} for the key {responseName}; otherwise create the entry with an empty ordered set. @@ -554,9 +554,9 @@ CollectSubfields(objectType, fields, variableValues): - For each {field} in {fields}: - Let {fieldSelectionSet} be the selection set of {field}. - If {fieldSelectionSet} is null or empty, continue to the next field. - - Let {fieldCollectedFieldMap} be the result of {CollectFields(objectType, + - Let {fieldCollectedFieldsMap} be the result of {CollectFields(objectType, fieldSelectionSet, variableValues)}. - - For each {responseName} and {subfields} in {fieldCollectedFieldMap}: + - For each {responseName} and {subfields} in {fieldCollectedFieldsMap}: - Let {fieldsForResponseName} be the _field set_ value in {collectedFieldsMap} for the key {responseName}; otherwise create the entry with an empty ordered set. From 7e8ae940212fe3d8930db2a8b5958f613fff1353 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:05:26 +0100 Subject: [PATCH 3/8] Reword to avoid 'During execution, ... before execution.' --- spec/Section 5 -- Validation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 982b9b3ad..88f1e4048 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -584,7 +584,7 @@ should be unambiguous. Therefore any two field selections which might both be encountered for the same object are only valid if they are equivalent. During execution, the simultaneous execution of fields with the same response -name is accomplished by {CollectSubfields()} before execution. +name is accomplished by performing {CollectSubfields()} before their execution. For simple hand-written GraphQL, this rule is obviously a clear developer error, however nested fragments can make this difficult to detect manually. From 63f68d651983f44822b7f13694ae2e6dccf91140 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:14:31 +0100 Subject: [PATCH 4/8] Serial execution relates to the set of fields, not each individual field --- spec/Section 6 -- Execution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index dc64446a2..c6eecd01c 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -369,8 +369,8 @@ continues until there are no more subfields to collect and execute. operation. A root selection set always selects from a _root operation type_. To execute the root selection set, the initial value being evaluated and the -root type must be known, as well as whether each field must be executed -serially, or normally by executing all fields in parallel (see +root type must be known, as well as whether the fields must be executed in a +series, or normally by executing all fields in parallel (see [Normal and Serial Execution](#sec-Normal-and-Serial-Execution). Executing the root selection set works similarly for queries (parallel), From 9a83fff464ad4487a5b87a2004d8ac9e7865e60a Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:22:32 +0100 Subject: [PATCH 5/8] Add missing close parenthesis --- spec/Section 6 -- Execution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index c6eecd01c..a15dd3b81 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -371,7 +371,7 @@ operation. A root selection set always selects from a _root operation type_. To execute the root selection set, the initial value being evaluated and the root type must be known, as well as whether the fields must be executed in a series, or normally by executing all fields in parallel (see -[Normal and Serial Execution](#sec-Normal-and-Serial-Execution). +[Normal and Serial Execution](#sec-Normal-and-Serial-Execution)). Executing the root selection set works similarly for queries (parallel), mutations (serial), and subscriptions (where it is executed for each event in From 5990d1c90d9fad6449893fdacebeedaddedcbc83 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:28:39 +0100 Subject: [PATCH 6/8] Remove duplicate 'by', specific algorithm is detailed in next paragraph --- spec/Section 6 -- Execution.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index a15dd3b81..1dbad59f4 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -396,10 +396,9 @@ executionMode): ### Field Collection Before execution, each _selection set_ is converted to a _collected fields map_ -by calling {CollectFields()} by collecting all fields with the same response -name, including those in referenced fragments, into an individual _field set_. -This ensures that multiple references to fields with the same response name will -only be executed once. +by collecting all fields with the same response name, including those in +referenced fragments, into an individual _field set_. This ensures that multiple +references to fields with the same response name will only be executed once. :: A _collected fields map_ is an ordered map where each entry is a _response name_ and its associated _field set_. A _collected fields map_ may be produced From 82654e408a2f48cda57ecb6d5fcc38539b0ea5a2 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:31:10 +0100 Subject: [PATCH 7/8] CollectFields() produces many _field set_ --- spec/Section 6 -- Execution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 1dbad59f4..932e760c8 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -435,8 +435,8 @@ fragment ExampleFragment on Query { } ``` -The depth-first-search order of the _field set_ produced by {CollectFields()} is -maintained through execution, ensuring that fields appear in the executed +The depth-first-search order of each _field set_ produced by {CollectFields()} +is maintained through execution, ensuring that fields appear in the executed response in a stable and predictable order. CollectFields(objectType, selectionSet, variableValues, visitedFragments): From eb622294f406f269dc0a42ac2decea8d853fdb22 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 2 Jul 2025 13:37:16 +0100 Subject: [PATCH 8/8] Minor edits --- spec/Section 6 -- Execution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 932e760c8..c615e526e 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -517,8 +517,8 @@ directives may be applied in either order since they apply commutatively. **Merging Selection Sets** -In order to execute the sub-selections of a object typed field, all _selection -sets_ of each field with the same response name of the parent _field set_ are +In order to execute the sub-selections of an object typed field, all _selection +sets_ of each field with the same response name in the parent _field set_ are merged together into a single _collected fields map_ representing the subfields to be executed next.