Skip to content

Commit

Permalink
Change name to 'SemanticNonNull' and syntax to bang prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
benjie committed Nov 24, 2023
1 parent 23fa23b commit 8395fd5
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 74 deletions.
6 changes: 3 additions & 3 deletions spec/Section 2 -- Language.md
Original file line number Diff line number Diff line change
Expand Up @@ -1239,10 +1239,10 @@ NonNullType :
- NamedType !
- ListType !

NullOnlyOnErrorType :
SemanticNonNullType :

- NamedType \*
- ListType \*
- ! NamedType
- ! ListType

GraphQL describes the types of data expected by arguments and variables. Input
types may be lists of another input type, or a non-null variant of any other
Expand Down
88 changes: 44 additions & 44 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -1859,7 +1859,7 @@ non-null input type as invalid.
**Type Validation**

1. A Non-Null type must not wrap another Non-Null type.
1. A Non-Null type must not wrap a Null-Only-On-Error type.
1. A Non-Null type must not wrap a Semantic-Non-Null type.

### Combining List and Non-Null

Expand Down Expand Up @@ -1893,82 +1893,82 @@ Following are examples of result coercion with various types and values:
| `[Int!]!` | `[1, 2, null]` | Error: Item cannot be null |
| `[Int!]!` | `[1, 2, Error]` | Error: Error occurred in item |

## Null-Only-On-Error
## Semantic-Non-Null

The GraphQL Null-Only-On-Error type is an alternative to the GraphQL Non-Null
The GraphQL Semantic-Non-Null type is an alternative to the GraphQL Non-Null
type to disallow null unless accompanied by a field error. This type wraps an
underlying type, and this type acts identically to that wrapped type, with the
exception that {null} will result in a field error being raised. A trailing
asterisk is used to denote a field that uses a Null-Only-On-Error type like
this: `name: String*`.
exception that {null} will result in a field error being raised. A leading
exclamation mark is used to denote a field that uses a Semantic-Non-Null type
like this: `name: !String`.

Null-Only-On-Error types are only valid for use as an _output type_; they must
Semantic-Non-Null types are only valid for use as an _output type_; they must
not be used as an _input type_.

**Nullable vs. Optional**

Fields that return Null-Only-On-Error types will never return the value {null}
if queried _unless_ an error has been logged for that field.
Fields that return Semantic-Non-Null types will never return the value {null} if
queried _unless_ an error has been logged for that field.

**Result Coercion**

To coerce the result of a Null-Only-On-Error type, the coercion of the wrapped
To coerce the result of a Semantic-Non-Null type, the coercion of the wrapped
type should be performed. If that result was not {null}, then the result of
coercing the Null-Only-On-Error type is that result. If that result was {null},
coercing the Semantic-Non-Null type is that result. If that result was {null},
then a _field error_ must be raised.

Note: When a _field error_ is raised on a Null-Only-On-Error value, the error
Note: When a _field error_ is raised on a Semantic-Non-Null value, the error
does not propagate to the parent field, instead {null} is used for the value.
For more information on this process, see
[Handling Field Errors](#sec-Handling-Field-Errors) within the Execution
section.

**Input Coercion**

Null-Only-On-Error types are never valid inputs.
Semantic-Non-Null types are never valid inputs.

**Type Validation**

1. A Null-Only-On-Error type must wrap an _output type_.
1. A Null-Only-On-Error type must not wrap another Null-Only-On-Error type.
1. A Null-Only-On-Error type must not wrap a Non-Null type.
1. A Semantic-Non-Null type must wrap an _output type_.
1. A Semantic-Non-Null type must not wrap another Semantic-Non-Null type.
1. A Semantic-Non-Null type must not wrap a Non-Null type.

### Combining List and Null-Only-On-Error
### Combining List and Semantic-Non-Null

The List and Null-Only-On-Error wrapping types can compose, representing more
complex types. The rules for result coercion of Lists and Null-Only-On-Error
The List and Semantic-Non-Null wrapping types can compose, representing more
complex types. The rules for result coercion of Lists and Semantic-Non-Null
types apply in a recursive fashion.

For example if the inner item type of a List is Null-Only-On-Error (e.g.
`[T*]`), then that List may not contain any {null} items unless associated field
errors were raised. However if the inner type of a Null-Only-On-Error is a List
(e.g. `[T]*`), then {null} is not accepted without an accompanying field error
being raised, however an empty list is accepted.
For example if the inner item type of a List is Semantic-Non-Null (e.g. `[!T]`),
then that List may not contain any {null} items unless associated field errors
were raised. However if the inner type of a Semantic-Non-Null is a List (e.g.
`![T]`), then {null} is not accepted without an accompanying field error being
raised, however an empty list is accepted.

Following are examples of result coercion with various types and values:

| Expected Type | Internal Value | Coerced Result |
| ------------- | --------------- | ------------------------------------------- |
| `[Int]*` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[Int]*` | `null` | `null` (With logged coercion error) |
| `[Int]*` | `[1, 2, null]` | `[1, 2, null]` |
| `[Int]*` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `[Int!]*` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[Int!]*` | `null` | `null` (With logged coercion error) |
| `[Int!]*` | `[1, 2, null]` | `null` (With logged coercion error) |
| `[Int!]*` | `[1, 2, Error]` | `null` (With logged error) |
| `[Int*]` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[Int*]` | `null` | `null` |
| `[Int*]` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `[Int*]` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `[Int*]!` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[Int*]!` | `null` | Error: Value cannot be null |
| `[Int*]!` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `[Int*]!` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `[Int*]*` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[Int*]*` | `null` | `null` (With logged coercion error) |
| `[Int*]*` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `[Int*]*` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `![Int]` | `[1, 2, 3]` | `[1, 2, 3]` |
| `![Int]` | `null` | `null` (With logged coercion error) |
| `![Int]` | `[1, 2, null]` | `[1, 2, null]` |
| `![Int]` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `![Int!]` | `[1, 2, 3]` | `[1, 2, 3]` |
| `![Int!]` | `null` | `null` (With logged coercion error) |
| `![Int!]` | `[1, 2, null]` | `null` (With logged coercion error) |
| `![Int!]` | `[1, 2, Error]` | `null` (With logged error) |
| `[!Int]` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[!Int]` | `null` | `null` |
| `[!Int]` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `[!Int]` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `[!Int]!` | `[1, 2, 3]` | `[1, 2, 3]` |
| `[!Int]!` | `null` | Error: Value cannot be null |
| `[!Int]!` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `[!Int]!` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |
| `![!Int]` | `[1, 2, 3]` | `[1, 2, 3]` |
| `![!Int]` | `null` | `null` (With logged coercion error) |
| `![!Int]` | `[1, 2, null]` | `[1, 2, null]` (With logged coercion error) |
| `![!Int]` | `[1, 2, Error]` | `[1, 2, null]` (With logged error) |

## Directives

Expand Down
46 changes: 22 additions & 24 deletions spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ enum __TypeKind {
INPUT_OBJECT
LIST
NON_NULL
NULL_ONLY_ON_ERROR
SEMANTIC_NON_NULL
}

type __Field {
name: String!
description: String
args(includeDeprecated: Boolean = false): [__InputValue!]!
type(includeNullOnlyOnError: Boolean! = false): __Type!
type(includeSemanticNonNull: Boolean! = false): __Type!
isDeprecated: Boolean!
deprecationReason: String
}
Expand Down Expand Up @@ -264,7 +264,7 @@ possible value of the `__TypeKind` enum:
- {"INPUT_OBJECT"}
- {"LIST"}
- {"NON_NULL"}
- {"NULL_ONLY_ON_ERROR"}
- {"SEMANTIC_NON_NULL"}

**Scalar**

Expand Down Expand Up @@ -403,34 +403,32 @@ required inputs for arguments and input object fields.
The modified type in the `ofType` field may itself be a modified List type,
allowing the representation of Non-Null of Lists. However it must not be a
modified Non-Null type to avoid a redundant Non-Null of Non-Null; nor may it be
a modified Null-Only-On-Error type since these types are mutually exclusive.
a modified Semantic-Non-Null type since these types are mutually exclusive.

Fields\:

- `kind` must return `__TypeKind.NON_NULL`.
- `ofType` must return a type of any kind except Non-Null and
Null-Only-On-Error.
- `ofType` must return a type of any kind except Non-Null and Semantic-Non-Null.
- All other fields must return {null}.

**Null-Only-On-Error**
**Semantic-Non-Null**

GraphQL types are nullable. The value {null} is a valid response for field type.

A Null-Only-On-Error type is a type modifier: it wraps another _output type_
instance in the `ofType` field. Null-Only-On-Error types do not allow {null} as
a response _unless_ an associated _field error_ has been raised.
A Semantic-Non-Null type is a type modifier: it wraps another _output type_
instance in the `ofType` field. Semantic-Non-Null types do not allow {null} as a
response _unless_ an associated _field error_ has been raised.

The modified type in the `ofType` field may itself be a modified List type,
allowing the representation of Null-Only-On-Error of Lists. However it must not
be a modified Null-Only-On-Error type to avoid a redundant Null-Only-On-Error of
Null-Only-On-Error; nor may it be a modified Non-Null type since these types are
allowing the representation of Semantic-Non-Null of Lists. However it must not
be a modified Semantic-Non-Null type to avoid a redundant Null-Only-On-Error of
Semantic-Non-Null; nor may it be a modified Non-Null type since these types are
mutually exclusive.

Fields\:

- `kind` must return `__TypeKind.NULL_ONLY_ON_ERROR`.
- `ofType` must return a type of any kind except Non-Null and
Null-Only-On-Error.
- `kind` must return `__TypeKind.SEMANTIC_NON_NULL`.
- `ofType` must return a type of any kind except Non-Null and Semantic-Non-Null.
- All other fields must return {null}.

### The \_\_Field Type
Expand All @@ -447,24 +445,24 @@ Fields\:
{true}, deprecated arguments are also returned.
- `type` must return a `__Type` that represents the type of value returned by
this field.
- Accepts the argument `includeNullOnlyOnError` which defaults to {false}. If
- Accepts the argument `includeSemanticNonNull` which defaults to {false}. If
{false}, let {fieldType} be the type of value returned by this field and
instead return a `__Type` that represents
{RecursivelyStripNullOnlyOnErrorTypes(fieldType)}.
{RecursivelyStripSemanticNonNullTypes(fieldType)}.
- `isDeprecated` returns {true} if this field should no longer be used,
otherwise {false}.
- `deprecationReason` optionally provides a reason why this field is deprecated.

RecursivelyStripNullOnlyOnErrorTypes(type):
RecursivelyStripSemanticNonNullTypes(type):

- If {type} is a Null-Only-On-Error type:
- If {type} is a Semantic-Non-Null type:
- Let {innerType} be the inner type of {type}.
- Return {RecursivelyStripNullOnlyOnErrorTypes(innerType)}.
- Return {RecursivelyStripSemanticNonNullTypes(innerType)}.
- Otherwise, return {type}.

Note: This algorithm recursively removes all Null-Only-On-Error type wrappers
(e.g. `[[Int*]!]*` would become `[[Int]!]`). This is to support legacy clients:
they can safely treat a Null-Only-On-Error type as the underlying nullable type.
Note: This algorithm recursively removes all Semantic-Non-Null type wrappers
(e.g. `![[!Int]!]` would become `[[Int]!]`). This is to support legacy clients:
they can safely treat a Semantic-Non-Null type as the underlying nullable type.

### The \_\_InputValue Type

Expand Down
6 changes: 3 additions & 3 deletions spec/Section 6 -- Execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ field execution process continues recursively.

CompleteValue(fieldType, fields, result, variableValues):

- If the {fieldType} is a Non-Null or a Null-Only-On-Error type:
- If the {fieldType} is a Non-Null or a Semantic-Non-Null type:
- Let {innerType} be the inner type of {fieldType}.
- Let {completedResult} be the result of calling {CompleteValue(innerType,
fields, result, variableValues)}.
Expand Down Expand Up @@ -806,5 +806,5 @@ If all fields from the root of the request to the source of the field error
return `Non-Null` types, then the {"data"} entry in the response should be
{null}.

Note: By the above, field errors that happen in `Null-Only-On-Error` types do
not propagate.
Note: By the above, field errors that happen in `Semantic-Non-Null` types do not
propagate.

0 comments on commit 8395fd5

Please sign in to comment.