Skip to content
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

[RFC] Input Objects accepting exactly @oneField #586

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions spec/Section 3 -- Type System.md
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,20 @@ Input object type extensions have the potential to be invalid if incorrectly def
the original Input Object.
5. Any directives provided must not already apply to the original Input Object type.

### Input Objects Requiring Exactly One Field

A GraphQL schema may wish to represent a situation where an input could take
one of many different options. When using the type system definition language,
`@oneField` is used to indicate that the input object requires exactly one
field be provided (and the value of that field must not be {null}):

```graphql
input UserUniqueCondition @oneField {
id: ID
username: String
organizationAndEmail: OrganizationAndEmailInput
}
```

## List

Expand Down Expand Up @@ -1650,6 +1664,12 @@ GraphQL implementations that support the type system definition language must
provide the `@deprecated` directive if representing deprecated portions of
the schema.

GraphQL implementations that support the type system definition language must
provide the `@oneField` directive if representing input types that implement
the
[Input Objects Requiring Exactly One Field](#input-objects-requiring-exactly-one-field)
feature.

Directives must only be used in the locations they are declared to belong in.
In this example, a directive is defined which can be used to annotate a field:

Expand Down Expand Up @@ -1778,3 +1798,31 @@ type ExampleType {
oldField: String @deprecated(reason: "Use `newField`.")
}
```

### @oneField


```graphql
directive @oneField on INPUT_OBJECT
```

The `@oneField` directive is used within the type system definition language to
indicate an input object where the user should specify exactly one field, such
as where the schema wishes to accept different types for an input.

The `@oneField` directive does not accept any arguments.

Any inputs of this type present in a query must provide one and only one field
from the input object, and that field (and only that field) is treated as
non-nullable for the purposes of validation.

In this example type definition, media blocks can be of different types, and
these are enumerated via a `@oneField` input object.

```graphql example
input MediaBlockInput @oneField {
post: PostInput
image: ImageInput
href: String
}
```
8 changes: 8 additions & 0 deletions spec/Section 4 -- Introspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ type __Type {
# should be non-null for ENUM only, must be null for the others
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]

# should be non-null for INPUT_OBJECT only, must be null for the others
requiresExactlyOneField: Boolean!
benjie marked this conversation as resolved.
Show resolved Hide resolved

# should be non-null for INPUT_OBJECT only, must be null for the others
inputFields: [__InputValue!]

Expand Down Expand Up @@ -331,7 +334,12 @@ Fields
* `kind` must return `__TypeKind.INPUT_OBJECT`.
* `name` must return a String.
* `description` may return a String or {null}.
* `requiresExactlyOneField` must return a Boolean
* `inputFields`: a list of `InputValue`.
* if `requiresExactlyOneField` is {true}:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other places we have "Type Validation" sub-sections. That would be a better place for this list set

* for each {inputValue} in {inputFields}
* the {type} of {inputValue} must not be Non-Null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This answered my question on the call

* the {defaultValue} of {inputValue} must be {null}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be no defaultValue instead of null since you don't want to allow field: Type = null

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spot on 👍

* All other fields must return {null}.


Expand Down
18 changes: 18 additions & 0 deletions spec/Section 5 -- Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,24 @@ arguments, an input object may have required fields. An input field is required
if it has a non-null type and does not have a default value. Otherwise, the
input object field is optional.

### Input Object With Requires Exactly One Field

**Formal Specification**

* For each Input Object in the document for which {requiresExactlyOneField} is {true}:
* Let {fields} be the fields provided by that Input Object.
* Let {fieldDefinitions} be the set of input field definitions of that Input Object.
* {fieldDefinitions} must contain exactly one entry
* For the sole {fieldDefinition} in {fieldDefinitions}:
* Let {fieldName} be the name of {fieldDefinition}.
* Let {field} be the input field in {fields} named {fieldName}
* Let {value} be the value of {field}.
* {value} must not be the {null} literal.

**Explanatory Text**

When an input object requires exactly one field, exactly one field must be
supplied and that field must not be null.

## Directives

Expand Down