From 39e593cb8b0d13a50997b3edaba5edd06d491abb Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 19 Feb 2021 15:45:42 +0000 Subject: [PATCH] @oneOf fields --- spec/Section 3 -- Type System.md | 53 ++++++++++++++++++++++++++++-- spec/Section 4 -- Introspection.md | 3 ++ spec/Section 5 -- Validation.md | 14 ++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index fb3d5d4bf..3713da402 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -818,6 +818,9 @@ of rules must be adhered to by every Object type in a GraphQL schema. characters {"__"} (two underscores). 2. The argument must accept a type where {IsInputType(argumentType)} returns {true}. + 3. If the field is a Oneof Field: + 1. The field must be nullable. + 2. The field must not have a default value. 3. An object type may declare that it implements one or more unique interfaces. 4. An object type must be a super-set of all interfaces it implements: 1. Let this object type be {objectType}. @@ -845,6 +848,8 @@ IsValidImplementation(type, implementedType): 2. Let {implementedFieldType} be the return type of {implementedField}. 3. {IsValidImplementationFieldType(fieldType, implementedFieldType)} must be {true}. + 6. {field} must be a Oneof Field if and only if {implementedField} is a + Oneof Field. IsValidImplementationFieldType(fieldType, implementedFieldType): 1. If {fieldType} is a Non-Null type: @@ -917,6 +922,30 @@ May yield the result: The type of an object field argument must be an input type (any type except an Object, Interface, or Union type). +**Oneof Fields** + +Oneof Fields are a special variant of Object Type fields where the type system +asserts that exactly one of the field's arguments must be set and non-null, all +others being omitted. This is useful for representing situations where an input +may be one of many different options. + +When using the type system definition language, the `@oneOf` directive is used +to indicate that a Field is a Oneof Field (and thus requires exactly one of its +arguments be provided): + +```graphql +type Query { + findUser( + byID: ID + byUsername: String + byEmail: String + byRegistrationNumber: Int + ): User @oneOf +} +``` + +In schema introspection, the `__Field.oneArgument` field will return {true} for +Oneof Fields, and {false} for all other Fields. ### Field Deprecation @@ -1160,6 +1189,9 @@ Interface types have the potential to be invalid if incorrectly defined. characters {"__"} (two underscores). 2. The argument must accept a type where {IsInputType(argumentType)} returns {true}. + 3. If the field is a Oneof Field: + 1. The field must be nullable. + 2. The field must not have a default value. 3. An interface type may declare that it implements one or more unique interfaces, but may not implement itself. 4. An interface type must be a super-set of all interfaces it implements: @@ -1880,7 +1912,8 @@ provide: - the `@deprecated` directive if representing deprecated portions of the schema; - the `@oneOf` directive if representing types that require exactly one field - (i.e. Oneof Input Objects). + (i.e. Oneof Input Objects) or fields that require exactly one argument (i.e. + Oneof Fields). **Custom Directives** @@ -2048,11 +2081,14 @@ type ExampleType { ### @oneOf ```graphql -directive @oneOf on INPUT_OBJECT +directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION ``` The `@oneOf` directive is used within the type system definition language -to indicate an Input Object is a Oneof Input Object. +to indicate: + +- an Input Object is a Oneof Input Object, or +- an Object Type's Field is a Oneof Field. ```graphql example input UserUniqueCondition @oneOf { @@ -2061,3 +2097,14 @@ input UserUniqueCondition @oneOf { organizationAndEmail: OrganizationAndEmailInput } ``` + +```graphql example +type Query { + findUser( + byID: ID + byUsername: String + byEmail: String + byRegistrationNumber: Int + ): User @oneOf +} +``` diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index c3d4d0a41..5b2f7fdb0 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -159,6 +159,7 @@ type __Field { type: __Type! isDeprecated: Boolean! deprecationReason: String + oneArgument: Boolean! } type __InputValue { @@ -385,6 +386,8 @@ Fields * `isDeprecated` returns {true} if this field should no longer be used, otherwise {false}. * `deprecationReason` optionally provides a reason why this field is deprecated. +* `oneArgument` must return {true} for Oneof Fields, {false} for all other + Fields. ### The __InputValue Type diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 64336718b..5cb8f9ba4 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -780,6 +780,20 @@ fragment missingRequiredArg on Arguments { } ``` +#### Oneof Fields Have Exactly One Argument + +* For each Oneof Field in the document: + * Let {arguments} be the arguments provided by the Field. + * {arguments} must contain exactly one entry. + * For the sole {argument} in {arguments}: + * Let {value} be the value of {argument}. + * {value} must not be the {null} literal. + +**Explanatory Text** + +Oneof Fields require that exactly one argument must be supplied and that +argument must not be null. + ## Fragments ### Fragment Declarations