Skip to content

Commit dddd4b8

Browse files
committed
Merge branch 'main' into oneof-v2
2 parents 59ad4b7 + bc4ddea commit dddd4b8

File tree

4 files changed

+87
-40
lines changed

4 files changed

+87
-40
lines changed

spec/Section 2 -- Language.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ GraphQL descriptions are provided as Markdown (as specified by
247247
[CommonMark](https://commonmark.org/)). Description strings (often
248248
{BlockString}) occur immediately before the definition they describe.
249249

250+
Descriptions in GraphQL executable documents are purely for documentation
251+
purposes. They MUST NOT affect the execution, validation, or response of a
252+
GraphQL document. It is safe to remove all descriptions and comments from
253+
executable documents without changing their behavior or results.
254+
250255
This is an example of a well-described operation:
251256

252257
```graphql example
@@ -279,11 +284,6 @@ fragment TimeMachineDetails on TimeMachine {
279284
}
280285
```
281286

282-
Descriptions in GraphQL executable documents are purely for documentation
283-
purposes. They MUST NOT affect the execution, validation, or response of a
284-
GraphQL document. It is safe to remove all descriptions and comments from
285-
executable documents without changing their behavior or results.
286-
287287
## Document
288288

289289
Document : Definition+

spec/Section 3 -- Type System.md

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ via introspection.
5858

5959
[Descriptions](#sec-Descriptions) allow GraphQL service designers to easily
6060
provide documentation which remains consistent with the capabilities of a
61-
GraphQL service. Descriptions provided as Markdown (as specified by
61+
GraphQL service. Descriptions should be provided as Markdown (as specified by
6262
[CommonMark](https://commonmark.org/)) for every definition in a type system.
6363

6464
GraphQL schema and all other definitions (e.g. types, fields, arguments, etc.)
@@ -775,8 +775,8 @@ type Person {
775775
}
776776
```
777777

778-
Valid operations must supply a _selection set_ for every field of an object
779-
type, so this operation is not valid:
778+
Valid operations must supply a _selection set_ for every field whose return type
779+
is an object type, so this operation is not valid:
780780

781781
```graphql counter-example
782782
{
@@ -938,6 +938,8 @@ of rules must be adhered to by every Object type in a GraphQL schema.
938938
returns {true}.
939939
4. If argument type is Non-Null and a default value is not defined:
940940
1. The `@deprecated` directive must not be applied to this argument.
941+
5. If the argument has a default value it must be compatible with
942+
{argumentType} as per the coercion rules for that type.
941943
3. An object type may declare that it implements one or more unique interfaces.
942944
4. An object type must be a super-set of all interfaces it implements:
943945
1. Let this object type be {objectType}.
@@ -1680,7 +1682,8 @@ defined by the input object type and for which a value exists. The resulting map
16801682
is constructed with the following rules:
16811683

16821684
- If no value is provided for a defined input object field and that field
1683-
definition provides a default value, the default value should be used. If no
1685+
definition provides a default value, the result of coercing the default value
1686+
according to the coercion rules of the input field type should be used. If no
16841687
default value is provided and the input object field's type is non-null, an
16851688
error should be raised. Otherwise, if the field is not required, then no entry
16861689
is added to the coerced unordered map.
@@ -1803,6 +1806,44 @@ input ExampleOneOfInputObject @oneOf {
18031806
3. If an Input Object references itself either directly or through referenced
18041807
Input Objects, at least one of the fields in the chain of references must be
18051808
either a nullable or a List type.
1809+
4. {InputObjectDefaultValueHasCycle(inputObject)} must be {false}.
1810+
1811+
InputObjectDefaultValueHasCycle(inputObject, defaultValue, visitedFields):
1812+
1813+
- If {defaultValue} is not provided, initialize it to an empty unordered map.
1814+
- If {visitedFields} is not provided, initialize it to the empty set.
1815+
- If {defaultValue} is a list:
1816+
- For each {itemValue} in {defaultValue}:
1817+
- If {InputObjectDefaultValueHasCycle(inputObject, itemValue,
1818+
visitedFields)}, return {true}.
1819+
- Otherwise, if {defaultValue} is an unordered map:
1820+
- For each field {field} in {inputObject}:
1821+
- If {InputFieldDefaultValueHasCycle(field, defaultValue, visitedFields)},
1822+
return {true}.
1823+
- Return {false}.
1824+
1825+
InputFieldDefaultValueHasCycle(field, defaultValue, visitedFields):
1826+
1827+
- Assert: {defaultValue} is an unordered map.
1828+
- Let {fieldType} be the type of {field}.
1829+
- Let {namedFieldType} be the underlying named type of {fieldType}.
1830+
- If {namedFieldType} is not an input object type:
1831+
- Return {false}.
1832+
- Let {fieldName} be the name of {field}.
1833+
- Let {fieldDefaultValue} be the value for {fieldName} in {defaultValue}.
1834+
- If {fieldDefaultValue} exists:
1835+
- Return {InputObjectDefaultValueHasCycle(namedFieldType, fieldDefaultValue,
1836+
visitedFields)}.
1837+
- Otherwise:
1838+
- Let {fieldDefaultValue} be the default value of {field}.
1839+
- If {fieldDefaultValue} does not exist:
1840+
- Return {false}.
1841+
- If {field} is within {visitedFields}:
1842+
- Return {true}.
1843+
- Let {nextVisitedFields} be a new set containing {field} and everything from
1844+
{visitedFields}.
1845+
- Return {InputObjectDefaultValueHasCycle(namedFieldType, fieldDefaultValue,
1846+
nextVisitedFields)}.
18061847

18071848
### Input Object Extensions
18081849

spec/Section 5 -- Validation.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,11 @@ CollectSubscriptionFields(objectType, selectionSet, visitedFragments):
356356
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
357357
with the next {selection} in {selectionSet}.
358358
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
359-
- Let {fragmentCollectedFieldMap} be the result of calling
359+
- Let {fragmentCollectedFieldsMap} be the result of calling
360360
{CollectSubscriptionFields(objectType, fragmentSelectionSet,
361361
visitedFragments)}.
362362
- For each {responseName} and {fragmentFields} in
363-
{fragmentCollectedFieldMap}:
363+
{fragmentCollectedFieldsMap}:
364364
- Let {fieldsForResponseKey} be the _field set_ value in
365365
{collectedFieldsMap} for the key {responseName}; otherwise create the
366366
entry with an empty ordered set.
@@ -371,11 +371,11 @@ CollectSubscriptionFields(objectType, selectionSet, visitedFragments):
371371
fragmentType)} is {false}, continue with the next {selection} in
372372
{selectionSet}.
373373
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
374-
- Let {fragmentCollectedFieldMap} be the result of calling
374+
- Let {fragmentCollectedFieldsMap} be the result of calling
375375
{CollectSubscriptionFields(objectType, fragmentSelectionSet,
376376
visitedFragments)}.
377377
- For each {responseName} and {fragmentFields} in
378-
{fragmentCollectedFieldMap}:
378+
{fragmentCollectedFieldsMap}:
379379
- Let {fieldsForResponseKey} be the _field set_ value in
380380
{collectedFieldsMap} for the key {responseName}; otherwise create the
381381
entry with an empty ordered set.
@@ -606,7 +606,7 @@ should be unambiguous. Therefore any two field selections which might both be
606606
encountered for the same object are only valid if they are equivalent.
607607

608608
During execution, the simultaneous execution of fields with the same response
609-
name is accomplished by {CollectSubfields()} before execution.
609+
name is accomplished by performing {CollectSubfields()} before their execution.
610610

611611
For simple hand-written GraphQL, this rule is obviously a clear developer error,
612612
however nested fragments can make this difficult to detect manually.

spec/Section 6 -- Execution.md

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,10 @@ CoerceVariableValues(schema, operation, variableValues):
110110
- Let {value} be the value provided in {variableValues} for the name
111111
{variableName}.
112112
- If {hasValue} is not {true} and {defaultValue} exists (including {null}):
113+
- Let {coercedDefaultValue} be the result of coercing {defaultValue}
114+
according to the input coercion rules of {variableType}.
113115
- Add an entry to {coercedValues} named {variableName} with the value
114-
{defaultValue}.
116+
{coercedDefaultValue}.
115117
- Otherwise if {variableType} is a Non-Nullable type, and either {hasValue} is
116118
not {true} or {value} is {null}, raise a _request error_.
117119
- Otherwise if {hasValue} is {true}:
@@ -367,9 +369,9 @@ continues until there are no more subfields to collect and execute.
367369
operation. A root selection set always selects from a _root operation type_.
368370

369371
To execute the root selection set, the initial value being evaluated and the
370-
root type must be known, as well as whether each field must be executed
371-
serially, or normally by executing all fields in parallel (see
372-
[Normal and Serial Execution](#sec-Normal-and-Serial-Execution).
372+
root type must be known, as well as whether the fields must be executed in a
373+
series, or normally by executing all fields in parallel (see
374+
[Normal and Serial Execution](#sec-Normal-and-Serial-Execution)).
373375

374376
Executing the root selection set works similarly for queries (parallel),
375377
mutations (serial), and subscriptions (where it is executed for each event in
@@ -394,10 +396,9 @@ executionMode):
394396
### Field Collection
395397

396398
Before execution, each _selection set_ is converted to a _collected fields map_
397-
by calling {CollectFields()} by collecting all fields with the same response
398-
name, including those in referenced fragments, into an individual _field set_.
399-
This ensures that multiple references to fields with the same response name will
400-
only be executed once.
399+
by collecting all fields with the same response name, including those in
400+
referenced fragments, into an individual _field set_. This ensures that multiple
401+
references to fields with the same response name will only be executed once.
401402

402403
:: A _collected fields map_ is an ordered map where each entry is a _response
403404
name_ and its associated _field set_. A _collected fields map_ may be produced
@@ -434,8 +435,8 @@ fragment ExampleFragment on Query {
434435
}
435436
```
436437

437-
The depth-first-search order of the _field set_ produced by {CollectFields()} is
438-
maintained through execution, ensuring that fields appear in the executed
438+
The depth-first-search order of each _field set_ produced by {CollectFields()}
439+
is maintained through execution, ensuring that fields appear in the executed
439440
response in a stable and predictable order.
440441

441442
CollectFields(objectType, selectionSet, variableValues, visitedFragments):
@@ -473,11 +474,11 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
473474
- If {DoesFragmentTypeApply(objectType, fragmentType)} is {false}, continue
474475
with the next {selection} in {selectionSet}.
475476
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
476-
- Let {fragmentCollectedFieldMap} be the result of calling
477+
- Let {fragmentCollectedFieldsMap} be the result of calling
477478
{CollectFields(objectType, fragmentSelectionSet, variableValues,
478479
visitedFragments)}.
479480
- For each {responseName} and {fragmentFields} in
480-
{fragmentCollectedFieldMap}:
481+
{fragmentCollectedFieldsMap}:
481482
- Let {fieldsForResponseName} be the _field set_ value in
482483
{collectedFieldsMap} for the key {responseName}; otherwise create the
483484
entry with an empty ordered set.
@@ -488,11 +489,11 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
488489
fragmentType)} is {false}, continue with the next {selection} in
489490
{selectionSet}.
490491
- Let {fragmentSelectionSet} be the top-level selection set of {selection}.
491-
- Let {fragmentCollectedFieldMap} be the result of calling
492+
- Let {fragmentCollectedFieldsMap} be the result of calling
492493
{CollectFields(objectType, fragmentSelectionSet, variableValues,
493494
visitedFragments)}.
494495
- For each {responseName} and {fragmentFields} in
495-
{fragmentCollectedFieldMap}:
496+
{fragmentCollectedFieldsMap}:
496497
- Let {fieldsForResponseName} be the _field set_ value in
497498
{collectedFieldsMap} for the key {responseName}; otherwise create the
498499
entry with an empty ordered set.
@@ -516,8 +517,8 @@ directives may be applied in either order since they apply commutatively.
516517

517518
**Merging Selection Sets**
518519

519-
In order to execute the sub-selections of a object typed field, all _selection
520-
sets_ of each field with the same response name of the parent _field set_ are
520+
In order to execute the sub-selections of an object typed field, all _selection
521+
sets_ of each field with the same response name in the parent _field set_ are
521522
merged together into a single _collected fields map_ representing the subfields
522523
to be executed next.
523524

@@ -552,9 +553,9 @@ CollectSubfields(objectType, fields, variableValues):
552553
- For each {field} in {fields}:
553554
- Let {fieldSelectionSet} be the selection set of {field}.
554555
- If {fieldSelectionSet} is null or empty, continue to the next field.
555-
- Let {fieldCollectedFieldMap} be the result of {CollectFields(objectType,
556+
- Let {fieldCollectedFieldsMap} be the result of {CollectFields(objectType,
556557
fieldSelectionSet, variableValues)}.
557-
- For each {responseName} and {subfields} in {fieldCollectedFieldMap}:
558+
- For each {responseName} and {subfields} in {fieldCollectedFieldsMap}:
558559
- Let {fieldsForResponseName} be the _field set_ value in
559560
{collectedFieldsMap} for the key {responseName}; otherwise create the
560561
entry with an empty ordered set.
@@ -749,20 +750,22 @@ CoerceArgumentValues(objectType, field, variableValues):
749750
- Let {argumentName} be the name of {argumentDefinition}.
750751
- Let {argumentType} be the expected type of {argumentDefinition}.
751752
- Let {defaultValue} be the default value for {argumentDefinition}.
752-
- Let {hasValue} be {true} if {argumentValues} provides a value for the name
753-
{argumentName}.
754753
- Let {argumentValue} be the value provided in {argumentValues} for the name
755754
{argumentName}.
756755
- If {argumentValue} is a {Variable}:
757756
- Let {variableName} be the name of {argumentValue}.
758-
- Let {hasValue} be {true} if {variableValues} provides a value for the name
759-
{variableName}.
760-
- Let {value} be the value provided in {variableValues} for the name
761-
{variableName}.
762-
- Otherwise, let {value} be {argumentValue}.
757+
- If {variableValues} provides a value for the name {variableName}:
758+
- Let {hasValue} be {true}.
759+
- Let {value} be the value provided in {variableValues} for the name
760+
{variableName}.
761+
- Otherwise if {argumentValues} provides a value for the name {argumentName}.
762+
- Let {hasValue} be {true}.
763+
- Let {value} be {argumentValue}.
763764
- If {hasValue} is not {true} and {defaultValue} exists (including {null}):
765+
- Let {coercedDefaultValue} be the result of coercing {defaultValue}
766+
according to the input coercion rules of {argumentType}.
764767
- Add an entry to {coercedValues} named {argumentName} with the value
765-
{defaultValue}.
768+
{coercedDefaultValue}.
766769
- Otherwise if {argumentType} is a Non-Nullable type, and either {hasValue} is
767770
not {true} or {value} is {null}, raise an _execution error_.
768771
- Otherwise if {hasValue} is {true}:
@@ -788,6 +791,9 @@ Note: Variable values are not coerced because they are expected to be coerced
788791
before executing the operation in {CoerceVariableValues()}, and valid operations
789792
must only allow usage of variables of appropriate types.
790793

794+
Note: Implementations are encouraged to optimize the coercion of an argument's
795+
default value by doing so only once and caching the resulting coerced value.
796+
791797
### Value Resolution
792798

793799
While nearly all of GraphQL execution can be described generically, ultimately

0 commit comments

Comments
 (0)