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: __typename should be valid at subscription root #806

Closed
wants to merge 1 commit 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 23 additions & 13 deletions spec/Section 5 -- Validation.md
Expand Up @@ -247,13 +247,14 @@ query getName {
* Let {subscriptionType} be the root Subscription type in {schema}.
* Let {selectionSet} be the top level selection set on {subscription}.
* Let {variableValues} be the empty set.
* Let {groupedFieldSet} be the result of
{CollectFields(subscriptionType, selectionSet, variableValues)}.
* {groupedFieldSet} must have exactly one entry.
* Let {groupedFieldSetExcludingIntrospection} be the result of
{CollectFields(subscriptionType, selectionSet, variableValues, true)}.
* {groupedFieldSetExcludingIntrospection} must have exactly one entry.

**Explanatory Text**

Subscription operations must have exactly one root field.
Subscription operations must have exactly one non-introspection root field.
(Subscription operations may have any number of introspection root fields.)

Valid examples:

Expand All @@ -279,6 +280,18 @@ fragment newMessageFields on Subscription {
}
```

Introspection fields are not counted. The following example is also valid:

```graphql counter-example
subscription sub {
newMessage {
body
sender
}
__typename
}
```

Invalid:

```graphql counter-example
Expand All @@ -305,22 +318,19 @@ fragment multipleSubscriptions on Subscription {
}
```

Introspection fields are counted. The following example is also invalid:
Introspection fields are not counted. The following example is also invalid:

```graphql counter-example
subscription sub {
newMessage {
body
sender
}
__typename
}
```

Note: While each subscription must have exactly one root field, a document may
contain any number of operations, each of which may contain different root
fields. When executed, a document containing multiple subscription operations
must provide the operation name as described in {GetOperation()}.
Note: While each subscription must have exactly one non-introspection root
field, a document may contain any number of operations, each of which may
contain different root fields. When executed, a document containing multiple
subscription operations must provide the operation name as described in
{GetOperation()}.

## Fields

Expand Down
25 changes: 14 additions & 11 deletions spec/Section 6 -- Execution.md
Expand Up @@ -250,10 +250,10 @@ CreateSourceEventStream(subscription, schema, variableValues, initialValue):

* Let {subscriptionType} be the root Subscription type in {schema}.
* Assert: {subscriptionType} is an Object type.
* Let {groupedFieldSet} be the result of
{CollectFields(subscriptionType, selectionSet, variableValues)}.
* If {groupedFieldSet} does not have exactly one entry, throw a query error.
* Let {fields} be the value of the first entry in {groupedFieldSet}.
* Let {groupedFieldSetExcludingIntrospection} be the result of
{CollectFields(subscriptionType, selectionSet, variableValues, true)}.
* If {groupedFieldSetExcludingIntrospection} does not have exactly one entry, throw a query error.
* Let {fields} be the value of the first entry in {groupedFieldSetExcludingIntrospection}.
* Let {fieldName} be the name of the first entry in {fields}.
Note: This value is unaffected if an alias is used.
* Let {field} be the first entry in {fields}.
Expand Down Expand Up @@ -477,8 +477,9 @@ The depth-first-search order of the field groups produced by {CollectFields()}
is maintained through execution, ensuring that fields appear in the executed
response in a stable and predictable order.

CollectFields(objectType, selectionSet, variableValues, visitedFragments):
CollectFields(objectType, selectionSet, variableValues, excludeIntrospection, visitedFragments):

* If {excludeIntrospection} is not provided, initialize it to {false}.
* If {visitedFragments} is not provided, initialize it to the empty set.
* Initialize {groupedFields} to an empty ordered map of lists.
* For each {selection} in {selectionSet}:
Expand All @@ -489,10 +490,12 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
* If {includeDirective}'s {if} argument is not {true} and is not a variable in {variableValues} with the value {true}, continue with the next
{selection} in {selectionSet}.
* If {selection} is a {Field}:
* Let {responseKey} be the response key of {selection} (the alias if defined, otherwise the field name).
* Let {groupForResponseKey} be the list in {groupedFields} for
{responseKey}; if no such list exists, create it as an empty list.
* Append {selection} to the {groupForResponseKey}.
* Let {fieldName} be the field name of {selection}.
* If {excludeIntrospection} is {false} or {fieldName} does not begin with the characters "__" (two underscores):
* Let {responseKey} be the response key of {selection} (the alias if defined, otherwise the field name).
* Let {groupForResponseKey} be the list in {groupedFields} for
{responseKey}; if no such list exists, create it as an empty list.
* Append {selection} to the {groupForResponseKey}.
* If {selection} is a {FragmentSpread}:
* Let {fragmentSpreadName} be the name of {selection}.
* If {fragmentSpreadName} is in {visitedFragments}, continue with the
Expand All @@ -507,7 +510,7 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
with the next {selection} in {selectionSet}.
* Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
* Let {fragmentGroupedFieldSet} be the result of calling
{CollectFields(objectType, fragmentSelectionSet, variableValues, visitedFragments)}.
{CollectFields(objectType, fragmentSelectionSet, variableValues, excludeIntrospection, visitedFragments)}.
* For each {fragmentGroup} in {fragmentGroupedFieldSet}:
* Let {responseKey} be the response key shared by all fields in {fragmentGroup}.
* Let {groupForResponseKey} be the list in {groupedFields} for
Expand All @@ -518,7 +521,7 @@ CollectFields(objectType, selectionSet, variableValues, visitedFragments):
* If {fragmentType} is not {null} and {DoesFragmentTypeApply(objectType, fragmentType)} is false, continue
with the next {selection} in {selectionSet}.
* Let {fragmentSelectionSet} be the top-level selection set of {selection}.
* Let {fragmentGroupedFieldSet} be the result of calling {CollectFields(objectType, fragmentSelectionSet, variableValues, visitedFragments)}.
* Let {fragmentGroupedFieldSet} be the result of calling {CollectFields(objectType, fragmentSelectionSet, variableValues, excludeIntrospection, visitedFragments)}.
* For each {fragmentGroup} in {fragmentGroupedFieldSet}:
* Let {responseKey} be the response key shared by all fields in {fragmentGroup}.
* Let {groupForResponseKey} be the list in {groupedFields} for
Expand Down