Skip to content

Commit 5994a65

Browse files
benjieyaacovCR
authored andcommitted
Default value coercion rules
1 parent 45ffddb commit 5994a65

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

spec/Section 3 -- Type System.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,8 @@ of rules must be adhered to by every Object type in a GraphQL schema.
882882
returns {true}.
883883
3. If argument type is Non-Null and a default value is not defined:
884884
- The `@deprecated` directive must not be applied to this argument.
885+
4. If the argument has a default value, it must be compatible with
886+
{argumentType} as per the coercion rules for that type.
885887
3. An object type may declare that it implements one or more unique interfaces.
886888
4. An object type must be a super-set of all interfaces it implements:
887889
1. Let this object type be {objectType}.
@@ -1598,7 +1600,8 @@ defined by the input object type and for which a value exists. The resulting map
15981600
is constructed with the following rules:
15991601

16001602
- If no value is provided for a defined input object field and that field
1601-
definition provides a default value, the default value should be used. If no
1603+
definition provides a default value, the result of coercing the default value
1604+
according to the coercion rules of the input field type should be used. If no
16021605
default value is provided and the input object field's type is non-null, an
16031606
error should be raised. Otherwise, if the field is not required, then no entry
16041607
is added to the coerced unordered map.
@@ -1663,6 +1666,42 @@ input ExampleInputObject {
16631666
3. If an Input Object references itself either directly or through referenced
16641667
Input Objects, at least one of the fields in the chain of references must be
16651668
either a nullable or a List type.
1669+
4. {DetectInputObjectDefaultValueCycle(inputObject)}.
1670+
1671+
DetectInputObjectDefaultValueCycle(inputObject, defaultValue, visitedFields):
1672+
1673+
- If {defaultValue} is not provided, initialize it to an empty unordered map.
1674+
- If {visitedFields} is not provided, initialize it to the empty set.
1675+
- If {defaultValue} is a list:
1676+
- For each {itemValue} in {defaultValue}:
1677+
- {DetectInputObjectDefaultValueCycle(inputObject, itemValue,
1678+
visitedFields)}.
1679+
- Otherwise:
1680+
- If {defaultValue} is not an unordered map:
1681+
- Return.
1682+
- For each field {field} in {inputObject}:
1683+
- {DetectInputFieldDefaultValueCycle(field, defaultValue, visitedFields)}.
1684+
1685+
DetectInputFieldDefaultValueCycle(field, defaultValue, visitedFields):
1686+
1687+
- Assert: {defaultValue} is an unordered map.
1688+
- Let {fieldType} be the type of {field}.
1689+
- Let {namedFieldType} be the underlying named type of {fieldType}.
1690+
- If {namedFieldType} is not an input object type:
1691+
- Return.
1692+
- Let {fieldName} be the name of {field}.
1693+
- Let {fieldDefaultValue} be the value for {fieldName} in {defaultValue}.
1694+
- If {fieldDefaultValue} exists:
1695+
- {DetectInputObjectDefaultValueCycle(namedFieldType, fieldDefaultValue,
1696+
visitedFields)}.
1697+
- Otherwise:
1698+
- Let {fieldDefaultValue} be the default value of {field}.
1699+
- If {fieldDefaultValue} does not exist:
1700+
- Return.
1701+
- {field} must not be within {visitedFields}.
1702+
- Add {field} to {visitedFields}.
1703+
- {DetectInputObjectDefaultValueCycle(namedFieldType, fieldDefaultValue,
1704+
visitedFields)}.
16661705

16671706
### Input Object Extensions
16681707

spec/Section 6 -- Execution.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,10 @@ CoerceVariableValues(schema, operation, variableValues):
9292
- Let {value} be the value provided in {variableValues} for the name
9393
{variableName}.
9494
- If {hasValue} is not {true} and {defaultValue} exists (including {null}):
95+
- Let {coercedDefaultValue} be the result of coercing {defaultValue}
96+
according to the input coercion rules of {variableType}.
9597
- Add an entry to {coercedValues} named {variableName} with the value
96-
{defaultValue}.
98+
{coercedDefaultValue}.
9799
- Otherwise if {variableType} is a Non-Nullable type, and either {hasValue} is
98100
not {true} or {value} is {null}, raise a _request error_.
99101
- Otherwise if {hasValue} is true:
@@ -616,8 +618,10 @@ CoerceArgumentValues(objectType, field, variableValues):
616618
{variableName}.
617619
- Otherwise, let {value} be {argumentValue}.
618620
- If {hasValue} is not {true} and {defaultValue} exists (including {null}):
621+
- Let {coercedDefaultValue} be the result of coercing {defaultValue}
622+
according to the input coercion rules of {argumentType}.
619623
- Add an entry to {coercedValues} named {argumentName} with the value
620-
{defaultValue}.
624+
{coercedDefaultValue}.
621625
- Otherwise if {argumentType} is a Non-Nullable type, and either {hasValue} is
622626
not {true} or {value} is {null}, raise a _field error_.
623627
- Otherwise if {hasValue} is true:
@@ -640,6 +644,10 @@ Note: Variable values are not coerced because they are expected to be coerced
640644
before executing the operation in {CoerceVariableValues()}, and valid operations
641645
must only allow usage of variables of appropriate types.
642646

647+
Note: As an optimization you might choose to coerce each {defaultValue} at
648+
schema build time and cache the results, then refer to this cache within
649+
{CoerceArgumentValues()} calls.
650+
643651
### Value Resolution
644652

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

0 commit comments

Comments
 (0)