parent
18b10af9f3
commit
eb83b60c9a
7 changed files with 96 additions and 16 deletions
|
@ -23,6 +23,7 @@
|
|||
- Add `specified_by_url` attribute argument to `#[derive(GraphQLScalarValue)]` and `#[graphql_scalar]` macros. ([#1003](https://github.com/graphql-rust/juniper/pull/1003), [#1000](https://github.com/graphql-rust/juniper/pull/1000))
|
||||
- Support `isRepeatable` field on directives. ([#1003](https://github.com/graphql-rust/juniper/pull/1003), [#1000](https://github.com/graphql-rust/juniper/pull/1000))
|
||||
- Support `__Schema.description`, `__Type.specifiedByURL` and `__Directive.isRepeatable` fields in introspection. ([#1003](https://github.com/graphql-rust/juniper/pull/1003), [#1000](https://github.com/graphql-rust/juniper/pull/1000))
|
||||
- Support directives on variables definitions. ([#1005](https://github.com/graphql-rust/juniper/pull/1005))
|
||||
|
||||
## Fixes
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ pub enum InputValue<S = DefaultScalarValue> {
|
|||
pub struct VariableDefinition<'a, S> {
|
||||
pub var_type: Spanning<Type<'a>>,
|
||||
pub default_value: Option<Spanning<InputValue<S>>>,
|
||||
pub directives: Option<Vec<Spanning<Directive<'a, S>>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
|
|
@ -451,6 +451,8 @@ where
|
|||
None
|
||||
};
|
||||
|
||||
let directives = parse_directives(parser, schema)?;
|
||||
|
||||
Ok(Spanning::start_end(
|
||||
&start_pos,
|
||||
&default_value
|
||||
|
@ -462,6 +464,7 @@ where
|
|||
VariableDefinition {
|
||||
var_type,
|
||||
default_value,
|
||||
directives: directives.map(|s| s.item),
|
||||
},
|
||||
),
|
||||
))
|
||||
|
|
|
@ -87,6 +87,8 @@ pub enum DirectiveLocation {
|
|||
FragmentDefinition,
|
||||
#[graphql(name = "FIELD_DEFINITION")]
|
||||
FieldDefinition,
|
||||
#[graphql(name = "VARIABLE_DEFINITION")]
|
||||
VariableDefinition,
|
||||
#[graphql(name = "FRAGMENT_SPREAD")]
|
||||
FragmentSpread,
|
||||
#[graphql(name = "INLINE_FRAGMENT")]
|
||||
|
@ -588,27 +590,28 @@ where
|
|||
|
||||
impl fmt::Display for DirectiveLocation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match *self {
|
||||
DirectiveLocation::Query => "query",
|
||||
DirectiveLocation::Mutation => "mutation",
|
||||
DirectiveLocation::Subscription => "subscription",
|
||||
DirectiveLocation::Field => "field",
|
||||
DirectiveLocation::FieldDefinition => "field definition",
|
||||
DirectiveLocation::FragmentDefinition => "fragment definition",
|
||||
DirectiveLocation::FragmentSpread => "fragment spread",
|
||||
DirectiveLocation::InlineFragment => "inline fragment",
|
||||
DirectiveLocation::Scalar => "scalar",
|
||||
DirectiveLocation::EnumValue => "enum value",
|
||||
f.write_str(match self {
|
||||
Self::Query => "query",
|
||||
Self::Mutation => "mutation",
|
||||
Self::Subscription => "subscription",
|
||||
Self::Field => "field",
|
||||
Self::FieldDefinition => "field definition",
|
||||
Self::FragmentDefinition => "fragment definition",
|
||||
Self::FragmentSpread => "fragment spread",
|
||||
Self::InlineFragment => "inline fragment",
|
||||
Self::VariableDefinition => "variable definition",
|
||||
Self::Scalar => "scalar",
|
||||
Self::EnumValue => "enum value",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> fmt::Display for TypeType<'a, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypeType::Concrete(t) => f.write_str(t.name().unwrap()),
|
||||
TypeType::List(ref i, _) => write!(f, "[{}]", i),
|
||||
TypeType::NonNull(ref i) => write!(f, "{}!", i),
|
||||
match self {
|
||||
Self::Concrete(t) => f.write_str(t.name().unwrap()),
|
||||
Self::List(i, _) => write!(f, "[{}]", i),
|
||||
Self::NonNull(i) => write!(f, "{}!", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1056,6 +1056,12 @@ pub(crate) fn schema_introspection_result() -> Value {
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "VARIABLE_DEFINITION",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "FRAGMENT_SPREAD",
|
||||
"description": null,
|
||||
|
@ -2387,6 +2393,11 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> Value {
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "VARIABLE_DEFINITION",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "FRAGMENT_SPREAD",
|
||||
"isDeprecated": false,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use crate::{
|
||||
ast::{Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType},
|
||||
ast::{
|
||||
Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType,
|
||||
VariableDefinition,
|
||||
},
|
||||
parser::Spanning,
|
||||
schema::model::DirectiveLocation,
|
||||
validation::{ValidatorContext, Visitor},
|
||||
|
@ -106,6 +109,24 @@ where
|
|||
assert_eq!(top, Some(DirectiveLocation::InlineFragment));
|
||||
}
|
||||
|
||||
fn enter_variable_definition(
|
||||
&mut self,
|
||||
_: &mut ValidatorContext<'a, S>,
|
||||
_: &'a (Spanning<&'a str>, VariableDefinition<S>),
|
||||
) {
|
||||
self.location_stack
|
||||
.push(DirectiveLocation::VariableDefinition);
|
||||
}
|
||||
|
||||
fn exit_variable_definition(
|
||||
&mut self,
|
||||
_: &mut ValidatorContext<'a, S>,
|
||||
_: &'a (Spanning<&'a str>, VariableDefinition<S>),
|
||||
) {
|
||||
let top = self.location_stack.pop();
|
||||
assert_eq!(top, Some(DirectiveLocation::VariableDefinition));
|
||||
}
|
||||
|
||||
fn enter_directive(
|
||||
&mut self,
|
||||
ctx: &mut ValidatorContext<'a, S>,
|
||||
|
@ -206,6 +227,33 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_unknown_directive_on_var_definition() {
|
||||
expect_fails_rule::<_, _, DefaultScalarValue>(
|
||||
factory,
|
||||
r#"query Foo(
|
||||
$var1: Int = 1 @skip(if: true) @unknown,
|
||||
$var2: String @deprecated
|
||||
) {
|
||||
name
|
||||
}"#,
|
||||
&[
|
||||
RuleError::new(
|
||||
&misplaced_error_message("skip", &DirectiveLocation::VariableDefinition),
|
||||
&[SourcePosition::new(42, 1, 31)],
|
||||
),
|
||||
RuleError::new(
|
||||
&unknown_error_message("unknown"),
|
||||
&[SourcePosition::new(58, 1, 47)],
|
||||
),
|
||||
RuleError::new(
|
||||
&misplaced_error_message("deprecated", &DirectiveLocation::VariableDefinition),
|
||||
&[SourcePosition::new(98, 2, 30)],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_many_unknown_directives() {
|
||||
expect_fails_rule::<_, _, DefaultScalarValue>(
|
||||
|
|
|
@ -141,6 +141,19 @@ fn visit_variable_definitions<'a, S, V>(
|
|||
visit_input_value(v, ctx, default_value);
|
||||
}
|
||||
|
||||
if let Some(dirs) = &def.1.directives {
|
||||
for directive in dirs {
|
||||
let directive_arguments = ctx
|
||||
.schema
|
||||
.directive_by_name(directive.item.name.item)
|
||||
.map(|d| &d.arguments);
|
||||
|
||||
v.enter_directive(ctx, directive);
|
||||
visit_arguments(v, ctx, directive_arguments, &directive.item.arguments);
|
||||
v.exit_directive(ctx, directive);
|
||||
}
|
||||
}
|
||||
|
||||
v.exit_variable_definition(ctx, def);
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue