Add subscription support to query parser (#430)
This commit is contained in:
parent
dcbb74155d
commit
b61aa900b1
11 changed files with 64 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
|||
# master
|
||||
|
||||
- No changes yet
|
||||
- Add ability to parse 'subscription'
|
||||
|
||||
# [[0.13.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.13.1)
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ pub struct Directive<'a, S> {
|
|||
pub enum OperationType {
|
||||
Query,
|
||||
Mutation,
|
||||
Subscription,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
|
|
@ -648,6 +648,10 @@ where
|
|||
None => return Err(GraphQLError::UnknownOperationName),
|
||||
};
|
||||
|
||||
if op.item.operation_type == OperationType::Subscription {
|
||||
return Err(GraphQLError::IsSubscription);
|
||||
}
|
||||
|
||||
let default_variable_values = op.item.variable_definitions.map(|defs| {
|
||||
defs.item
|
||||
.items
|
||||
|
@ -683,6 +687,7 @@ where
|
|||
.schema
|
||||
.mutation_type()
|
||||
.expect("No mutation type found"),
|
||||
OperationType::Subscription => unreachable!(),
|
||||
};
|
||||
|
||||
let executor = Executor {
|
||||
|
@ -705,6 +710,7 @@ where
|
|||
OperationType::Mutation => {
|
||||
executor.resolve_into_value(&root_node.mutation_info, &root_node.mutation_type)
|
||||
}
|
||||
OperationType::Subscription => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,10 @@ impl<'a> ser::Serialize for GraphQLError<'a> {
|
|||
message: "Unknown operation",
|
||||
}]
|
||||
.serialize(serializer),
|
||||
GraphQLError::IsSubscription => [SerializeHelper {
|
||||
message: "Expected query, got subscription",
|
||||
}]
|
||||
.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,7 @@ pub enum GraphQLError<'a> {
|
|||
NoOperationProvided,
|
||||
MultipleOperationsProvided,
|
||||
UnknownOperationName,
|
||||
IsSubscription,
|
||||
}
|
||||
|
||||
/// Execute a query in a provided schema
|
||||
|
|
|
@ -56,9 +56,12 @@ where
|
|||
S: ScalarValue,
|
||||
{
|
||||
match parser.peek().item {
|
||||
Token::CurlyOpen | Token::Name("query") | Token::Name("mutation") => Ok(
|
||||
Definition::Operation(parse_operation_definition(parser, schema)?),
|
||||
),
|
||||
Token::CurlyOpen
|
||||
| Token::Name("query")
|
||||
| Token::Name("mutation")
|
||||
| Token::Name("subscription") => Ok(Definition::Operation(parse_operation_definition(
|
||||
parser, schema,
|
||||
)?)),
|
||||
Token::Name("fragment") => Ok(Definition::Fragment(parse_fragment_definition(
|
||||
parser, schema,
|
||||
)?)),
|
||||
|
@ -95,6 +98,7 @@ where
|
|||
let op = match operation_type.item {
|
||||
OperationType::Query => Some(schema.concrete_query_type()),
|
||||
OperationType::Mutation => schema.concrete_mutation_type(),
|
||||
OperationType::Subscription => schema.concrete_subscription_type(),
|
||||
};
|
||||
let fields = op.and_then(|m| m.fields(schema));
|
||||
let fields = fields.as_ref().map(|c| c as &[_]);
|
||||
|
@ -394,6 +398,7 @@ fn parse_operation_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Operatio
|
|||
match parser.peek().item {
|
||||
Token::Name("query") => Ok(parser.next()?.map(|_| OperationType::Query)),
|
||||
Token::Name("mutation") => Ok(parser.next()?.map(|_| OperationType::Mutation)),
|
||||
Token::Name("subscription") => Ok(parser.next()?.map(|_| OperationType::Subscription)),
|
||||
_ => Err(parser.next()?.map(ParseError::UnexpectedToken)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ pub struct DirectiveType<'a, S> {
|
|||
pub enum DirectiveLocation {
|
||||
Query,
|
||||
Mutation,
|
||||
Subscription,
|
||||
Field,
|
||||
#[graphql(name = "FRAGMENT_DEFINITION")]
|
||||
FragmentDefinition,
|
||||
|
@ -243,6 +244,18 @@ impl<'a, S> SchemaType<'a, S> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn subscription_type(&self) -> Option<TypeType<S>> {
|
||||
// subscription is not yet in `RootNode`,
|
||||
// so return `None` for now
|
||||
None
|
||||
}
|
||||
|
||||
pub fn concrete_subscription_type(&self) -> Option<&MetaType<S>> {
|
||||
// subscription is not yet in `RootNode`,
|
||||
// so return `None` for now
|
||||
None
|
||||
}
|
||||
|
||||
pub fn type_list(&self) -> Vec<TypeType<S>> {
|
||||
self.types.values().map(|t| TypeType::Concrete(t)).collect()
|
||||
}
|
||||
|
@ -452,6 +465,7 @@ impl fmt::Display for DirectiveLocation {
|
|||
f.write_str(match *self {
|
||||
DirectiveLocation::Query => "query",
|
||||
DirectiveLocation::Mutation => "mutation",
|
||||
DirectiveLocation::Subscription => "subscription",
|
||||
DirectiveLocation::Field => "field",
|
||||
DirectiveLocation::FragmentDefinition => "fragment definition",
|
||||
DirectiveLocation::FragmentSpread => "fragment spread",
|
||||
|
|
|
@ -104,9 +104,8 @@ where
|
|||
self.mutation_type()
|
||||
}
|
||||
|
||||
// Included for compatibility with the introspection query in GraphQL.js
|
||||
fn subscription_type(&self) -> Option<TypeType<S>> {
|
||||
None
|
||||
self.subscription_type()
|
||||
}
|
||||
|
||||
fn directives(&self) -> Vec<&DirectiveType<S>> {
|
||||
|
|
|
@ -997,6 +997,12 @@ pub(crate) fn schema_introspection_result() -> value::Value {
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "SUBSCRIPTION",
|
||||
"description": Null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "FIELD",
|
||||
"description": Null,
|
||||
|
@ -2204,6 +2210,11 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> value::Value
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "SUBSCRIPTION",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "FIELD",
|
||||
"isDeprecated": false,
|
||||
|
|
|
@ -28,6 +28,7 @@ where
|
|||
self.location_stack.push(match op.item.operation_type {
|
||||
OperationType::Query => DirectiveLocation::Query,
|
||||
OperationType::Mutation => DirectiveLocation::Mutation,
|
||||
OperationType::Subscription => DirectiveLocation::Subscription,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,11 @@ where
|
|||
_: &'a Spanning<Operation<S>>,
|
||||
) {
|
||||
let top = self.location_stack.pop();
|
||||
assert!(top == Some(DirectiveLocation::Query) || top == Some(DirectiveLocation::Mutation));
|
||||
assert!(
|
||||
top == Some(DirectiveLocation::Query)
|
||||
|| top == Some(DirectiveLocation::Mutation)
|
||||
|| top == Some(DirectiveLocation::Subscription)
|
||||
);
|
||||
}
|
||||
|
||||
fn enter_field(&mut self, _: &mut ValidatorContext<'a, S>, _: &'a Spanning<Field<S>>) {
|
||||
|
|
|
@ -64,6 +64,17 @@ fn visit_definitions<'a, S, V>(
|
|||
.schema
|
||||
.concrete_mutation_type()
|
||||
.map(|t| Type::NonNullNamed(Cow::Borrowed(t.name().unwrap()))),
|
||||
Definition::Operation(Spanning {
|
||||
item:
|
||||
Operation {
|
||||
operation_type: OperationType::Subscription,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) => ctx
|
||||
.schema
|
||||
.concrete_subscription_type()
|
||||
.map(|t| Type::NonNullNamed(Cow::Borrowed(t.name().unwrap()))),
|
||||
};
|
||||
|
||||
ctx.with_pushed_type(def_type.as_ref(), |ctx| {
|
||||
|
|
Loading…
Reference in a new issue