Astroport.ONE/venv/lib/python3.11/site-packages/graphql/validation/rules/single_field_subscriptions.py
2024-03-01 16:15:45 +01:00

86 lines
3.1 KiB
Python

from typing import Any, Dict, cast
from ...error import GraphQLError
from ...execution.collect_fields import collect_fields
from ...language import (
FieldNode,
FragmentDefinitionNode,
OperationDefinitionNode,
OperationType,
)
from . import ValidationRule
__all__ = ["SingleFieldSubscriptionsRule"]
class SingleFieldSubscriptionsRule(ValidationRule):
"""Subscriptions must only include a single non-introspection field.
A GraphQL subscription is valid only if it contains a single root field and
that root field is not an introspection field.
See https://spec.graphql.org/draft/#sec-Single-root-field
"""
def enter_operation_definition(
self, node: OperationDefinitionNode, *_args: Any
) -> None:
if node.operation != OperationType.SUBSCRIPTION:
return
schema = self.context.schema
subscription_type = schema.subscription_type
if subscription_type:
operation_name = node.name.value if node.name else None
variable_values: Dict[str, Any] = {}
document = self.context.document
fragments: Dict[str, FragmentDefinitionNode] = {
definition.name.value: definition
for definition in document.definitions
if isinstance(definition, FragmentDefinitionNode)
}
fields = collect_fields(
schema,
fragments,
variable_values,
subscription_type,
node.selection_set,
)
if len(fields) > 1:
field_selection_lists = list(fields.values())
extra_field_selection_lists = field_selection_lists[1:]
extra_field_selection = [
field
for fields in extra_field_selection_lists
for field in (
fields
if isinstance(fields, list)
else [cast(FieldNode, fields)]
)
]
self.report_error(
GraphQLError(
(
"Anonymous Subscription"
if operation_name is None
else f"Subscription '{operation_name}'"
)
+ " must select only one top level field.",
extra_field_selection,
)
)
for field_nodes in fields.values():
field = field_nodes[0]
field_name = field.name.value
if field_name.startswith("__"):
self.report_error(
GraphQLError(
(
"Anonymous Subscription"
if operation_name is None
else f"Subscription '{operation_name}'"
)
+ " must not select an introspection top level field.",
field_nodes,
)
)