-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Spec edits for incremental delivery, Execution: CollectFields #1234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: incremental-integration
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -405,7 +405,7 @@ name_ and its associated _field set_. A _collected fields map_ may be produced | |||||||||||||||||||
| from a selection set via {CollectFields()} or from the selection sets of all | ||||||||||||||||||||
| entries of a _field set_ via {CollectSubfields()}. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| :: A _field set_ is an ordered set of selected fields that share the same | ||||||||||||||||||||
| :: A _field set_ is an ordered set of _field details_ that share the same | ||||||||||||||||||||
| _response name_ (the field alias if defined, otherwise the field's name). | ||||||||||||||||||||
| Validation ensures each field in the set has the same name and arguments, | ||||||||||||||||||||
| however each may have different subfields (see: | ||||||||||||||||||||
|
|
@@ -439,10 +439,46 @@ 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): | ||||||||||||||||||||
| CollectFields(objectType, selectionSet, variableValues, deferUsage, | ||||||||||||||||||||
| visitedFragments): | ||||||||||||||||||||
|
|
||||||||||||||||||||
| The {CollectFields()} algorithm makes use of the following data types: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| :: A _defer usage_ is an unordered map representing the usage of a `@defer` | ||||||||||||||||||||
| directive within a given operation. _Defer usage_ are "abstract" in that they | ||||||||||||||||||||
| include information about the `@defer` directive from the AST of the GraphQL | ||||||||||||||||||||
| document. A single _defer usage_ may be used to create many "concrete" Delivery | ||||||||||||||||||||
| Groups when a `@defer` is included within a list type. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| A _defer usage_ contains the following information: | ||||||||||||||||||||
|
Comment on lines
+447
to
+453
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update algorithm references to defer usage to require a map datastructure |
||||||||||||||||||||
|
|
||||||||||||||||||||
| - {label}: the `label` argument provided by the given `@defer` directive, if | ||||||||||||||||||||
| any, otherwise {undefined}. | ||||||||||||||||||||
| - {parentDeferUsage}: a defer usage corresponding to the `@defer` directive | ||||||||||||||||||||
| enclosing this `@defer` directive, if any, otherwise {undefined}. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| The {parentDeferUsage} entry is used to build distinct Execution Groups as | ||||||||||||||||||||
| discussed within the Execution Plan Generation section below. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| :: A _field detail_ is an unordered map containing the following entries: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - {field}: the field selection. | ||||||||||||||||||||
| - {deferUsage}: the _defer usage_ enclosing the selection, if any, otherwise | ||||||||||||||||||||
| {undefined}. | ||||||||||||||||||||
|
Comment on lines
+466
to
+467
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| :: A _collected fields map_ is an ordered map of _response name_ to lists of | ||||||||||||||||||||
| Field Details. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| The {CollectFields()} algorithm returns: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - {collectedFieldsMap}: the _collected fields map_ for the fields in the | ||||||||||||||||||||
| selection set. | ||||||||||||||||||||
| - {newDeferUsages}: a list of new _defer usage_ encountered during this field | ||||||||||||||||||||
| collection. | ||||||||||||||||||||
|
Comment on lines
+472
to
+477
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| - If {visitedFragments} is not provided, initialize it to the empty set. | ||||||||||||||||||||
| - Initialize {collectedFieldsMap} to an empty ordered map of ordered sets. | ||||||||||||||||||||
| - Initialize {newDeferUsages} to an empty list. | ||||||||||||||||||||
| - For each {selection} in {selectionSet}: | ||||||||||||||||||||
| - If {selection} provides the directive `@skip`, let {skipDirective} be that | ||||||||||||||||||||
| directive. | ||||||||||||||||||||
|
|
@@ -457,15 +493,26 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments): | |||||||||||||||||||
| - If {selection} is a {Field}: | ||||||||||||||||||||
| - Let {responseName} be the _response name_ of {selection} (the alias if | ||||||||||||||||||||
| defined, otherwise the field name). | ||||||||||||||||||||
| - Let {fieldDetails} be a new unordered map containing {field} and | ||||||||||||||||||||
| {deferUsage}. | ||||||||||||||||||||
| - Set the corresponding entries on {fieldDetails} to {selection} and | ||||||||||||||||||||
| {deferUsage}, respectively. | ||||||||||||||||||||
| - Let {fieldsForResponseName} be the _field set_ value in | ||||||||||||||||||||
| {collectedFieldsMap} for the key {responseName}; otherwise create the | ||||||||||||||||||||
| entry with an empty ordered set. | ||||||||||||||||||||
| - Add {selection} to the {fieldsForResponseName}. | ||||||||||||||||||||
| - Add {fieldDetails} to the {fieldsForResponseName}. | ||||||||||||||||||||
| - If {selection} is a {FragmentSpread}: | ||||||||||||||||||||
| - Let {fragmentSpreadName} be the name of {selection}. | ||||||||||||||||||||
| - If {selection} provides the directive `@defer` and its {if} argument is | ||||||||||||||||||||
| not {false} and is not a variable in {variableValues} with the value | ||||||||||||||||||||
| {false}: | ||||||||||||||||||||
| - Let {deferDirective} be that directive. | ||||||||||||||||||||
| - If this execution is for a subscription operation, raise an _execution | ||||||||||||||||||||
| error_. | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
| - If {fragmentSpreadName} is in {visitedFragments}, continue with the next | ||||||||||||||||||||
| {selection} in {selectionSet}. | ||||||||||||||||||||
| - Add {fragmentSpreadName} to {visitedFragments}. | ||||||||||||||||||||
| - If {deferDirective} is not defined: | ||||||||||||||||||||
| - Add {fragmentSpreadName} to {visitedFragments}. | ||||||||||||||||||||
|
Comment on lines
+514
to
+515
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. needs to be updated to mirror what's in graphql-js https://github.com/graphql/graphql-js/blob/17.x.x/src/execution/collectFields.ts#L294-L314 |
||||||||||||||||||||
| - Let {fragment} be the Fragment in the current Document whose name is | ||||||||||||||||||||
| {fragmentSpreadName}. | ||||||||||||||||||||
| - If no such {fragment} exists, continue with the next {selection} in | ||||||||||||||||||||
|
|
@@ -474,31 +521,51 @@ 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 {fragmentCollectedFieldsMap} be the result of calling | ||||||||||||||||||||
| {CollectFields(objectType, fragmentSelectionSet, variableValues, | ||||||||||||||||||||
| visitedFragments)}. | ||||||||||||||||||||
| - For each {responseName} and {fragmentFields} in | ||||||||||||||||||||
| - If {deferDirective} is defined: | ||||||||||||||||||||
| - Let {label} be the corresponding entry on {deferDirective}. | ||||||||||||||||||||
| - Let {parentDeferUsage} be {deferUsage}. | ||||||||||||||||||||
| - Let {fragmentDeferUsage} be an unordered map containing {label} and | ||||||||||||||||||||
| {parentDeferUsage}. | ||||||||||||||||||||
| - Otherwise, let {fragmentDeferUsage} be {deferUsage}. | ||||||||||||||||||||
| - Let {fragmentCollectedFieldsMap} and {fragmentNewDeferUsages} be the | ||||||||||||||||||||
| result of calling {CollectFields(objectType, fragmentSelectionSet, | ||||||||||||||||||||
| variableValues, fragmentDeferUsage, visitedFragments)}. | ||||||||||||||||||||
| - For each {responseName} and {fragmentFieldSet} in | ||||||||||||||||||||
| {fragmentCollectedFieldsMap}: | ||||||||||||||||||||
| - Let {fieldsForResponseName} be the _field set_ value in | ||||||||||||||||||||
| {collectedFieldsMap} for the key {responseName}; otherwise create the | ||||||||||||||||||||
| entry with an empty ordered set. | ||||||||||||||||||||
| - Add each item from {fragmentFields} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Add each item from {fragmentFieldSet} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Append all items in {fragmentNewDeferUsages} to {newDeferUsages}. | ||||||||||||||||||||
| - If {selection} is an {InlineFragment}: | ||||||||||||||||||||
| - Let {fragmentType} be the type condition on {selection}. | ||||||||||||||||||||
| - If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType, | ||||||||||||||||||||
| fragmentType)} is {false}, continue with the next {selection} in | ||||||||||||||||||||
| {selectionSet}. | ||||||||||||||||||||
| - Let {fragmentSelectionSet} be the top-level selection set of {selection}. | ||||||||||||||||||||
| - Let {fragmentCollectedFieldsMap} be the result of calling | ||||||||||||||||||||
| {CollectFields(objectType, fragmentSelectionSet, variableValues, | ||||||||||||||||||||
| visitedFragments)}. | ||||||||||||||||||||
| - For each {responseName} and {fragmentFields} in | ||||||||||||||||||||
| - If {selection} provides the directive `@defer` and its {if} argument is | ||||||||||||||||||||
| not {false} and is not a variable in {variableValues} with the value | ||||||||||||||||||||
| {false}: | ||||||||||||||||||||
| - Let {deferDirective} be that directive. | ||||||||||||||||||||
| - If this execution is for a subscription operation, raise an _execution | ||||||||||||||||||||
| error_. | ||||||||||||||||||||
| - If {deferDirective} is defined: | ||||||||||||||||||||
| - Let {label} be the corresponding entry on {deferDirective}. | ||||||||||||||||||||
| - Let {parentDeferUsage} be {deferUsage}. | ||||||||||||||||||||
| - Let {fragmentDeferUsage} be an unordered map containing {label} and | ||||||||||||||||||||
| {parentDeferUsage}. | ||||||||||||||||||||
| - Otherwise, let {fragmentDeferUsage} be {deferUsage}. | ||||||||||||||||||||
| - Let {fragmentCollectedFieldsMap} and {fragmentNewDeferUsages} be the | ||||||||||||||||||||
| result of calling {CollectFields(objectType, fragmentSelectionSet, | ||||||||||||||||||||
| variableValues, fragmentDeferUsage, visitedFragments)}. | ||||||||||||||||||||
| - For each {responseName} and {fragmentFieldSet} in | ||||||||||||||||||||
| {fragmentCollectedFieldsMap}: | ||||||||||||||||||||
| - Let {fieldsForResponseName} be the _field set_ value in | ||||||||||||||||||||
| {collectedFieldsMap} for the key {responseName}; otherwise create the | ||||||||||||||||||||
| entry with an empty ordered set. | ||||||||||||||||||||
| - Append each item from {fragmentFields} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Return {collectedFieldsMap}. | ||||||||||||||||||||
| - Add each item from {fragmentFieldSet} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Append all items in {fragmentNewDeferUsages} to {newDeferUsages}. | ||||||||||||||||||||
| - Return {collectedFieldsMap} and {newDeferUsages}. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| DoesFragmentTypeApply(objectType, fragmentType): | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -515,6 +582,10 @@ DoesFragmentTypeApply(objectType, fragmentType): | |||||||||||||||||||
| Note: The steps in {CollectFields()} evaluating the `@skip` and `@include` | ||||||||||||||||||||
| directives may be applied in either order since they apply commutatively. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Note: When completing a List field, the {CollectFields} algorithm is invoked | ||||||||||||||||||||
| with the same arguments for each element of the list. GraphQL Services may | ||||||||||||||||||||
| choose to memoize their implementations of {CollectFields}. | ||||||||||||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make this a stronger recommendation and explain why |
||||||||||||||||||||
|
|
||||||||||||||||||||
| **Merging Selection Sets** | ||||||||||||||||||||
|
|
||||||||||||||||||||
| In order to execute the sub-selections of an object typed field, all _selection | ||||||||||||||||||||
|
|
@@ -550,20 +621,23 @@ resolved in the same phase with the same value. | |||||||||||||||||||
| CollectSubfields(objectType, fields, variableValues): | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - Let {collectedFieldsMap} be an empty ordered map of ordered sets. | ||||||||||||||||||||
| - For each {field} in {fields}: | ||||||||||||||||||||
| - Let {newDeferUsages} be an empty list. | ||||||||||||||||||||
| - For each {fieldDetails} in {fields}: | ||||||||||||||||||||
| - Let {field} and {deferUsage} be the corresponding entries on {fieldDetails}. | ||||||||||||||||||||
| - Let {fieldSelectionSet} be the selection set of {field}. | ||||||||||||||||||||
| - If {fieldSelectionSet} is null or empty, continue to the next field. | ||||||||||||||||||||
| - Let {fieldCollectedFieldsMap} be the result of {CollectFields(objectType, | ||||||||||||||||||||
| fieldSelectionSet, variableValues)}. | ||||||||||||||||||||
| - For each {responseName} and {subfields} in {fieldCollectedFieldsMap}: | ||||||||||||||||||||
| - Let {subCollectedFieldsMap} and {subNewDeferUsages} be the result of | ||||||||||||||||||||
| {CollectFields(objectType, fieldSelectionSet, variableValues, deferUsage)}. | ||||||||||||||||||||
| - For each {responseName} and {subfields} in {subCollectedFieldsMap}: | ||||||||||||||||||||
| - Let {fieldsForResponseName} be the _field set_ value in | ||||||||||||||||||||
| {collectedFieldsMap} for the key {responseName}; otherwise create the | ||||||||||||||||||||
| entry with an empty ordered set. | ||||||||||||||||||||
| - Add each fields from {subfields} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Return {collectedFieldsMap}. | ||||||||||||||||||||
| - Add each item from {subfields} to {fieldsForResponseName}. | ||||||||||||||||||||
| - Append all items in {subNewDeferUsages} to {newDeferUsages}. | ||||||||||||||||||||
| - Return {collectedFieldsMap} and {newDeferUsages}. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Note: All the {fields} passed to {CollectSubfields()} share the same _response | ||||||||||||||||||||
| name_. | ||||||||||||||||||||
| Note: All the {fieldDetailsList} passed to {CollectSubfields()} share the same | ||||||||||||||||||||
| _response name_. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ### Executing Collected Fields | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to directly above the algorithm definition