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))
|
- 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 `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 `__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
|
## Fixes
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub enum InputValue<S = DefaultScalarValue> {
|
||||||
pub struct VariableDefinition<'a, S> {
|
pub struct VariableDefinition<'a, S> {
|
||||||
pub var_type: Spanning<Type<'a>>,
|
pub var_type: Spanning<Type<'a>>,
|
||||||
pub default_value: Option<Spanning<InputValue<S>>>,
|
pub default_value: Option<Spanning<InputValue<S>>>,
|
||||||
|
pub directives: Option<Vec<Spanning<Directive<'a, S>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
|
|
@ -451,6 +451,8 @@ where
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let directives = parse_directives(parser, schema)?;
|
||||||
|
|
||||||
Ok(Spanning::start_end(
|
Ok(Spanning::start_end(
|
||||||
&start_pos,
|
&start_pos,
|
||||||
&default_value
|
&default_value
|
||||||
|
@ -462,6 +464,7 @@ where
|
||||||
VariableDefinition {
|
VariableDefinition {
|
||||||
var_type,
|
var_type,
|
||||||
default_value,
|
default_value,
|
||||||
|
directives: directives.map(|s| s.item),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
|
@ -87,6 +87,8 @@ pub enum DirectiveLocation {
|
||||||
FragmentDefinition,
|
FragmentDefinition,
|
||||||
#[graphql(name = "FIELD_DEFINITION")]
|
#[graphql(name = "FIELD_DEFINITION")]
|
||||||
FieldDefinition,
|
FieldDefinition,
|
||||||
|
#[graphql(name = "VARIABLE_DEFINITION")]
|
||||||
|
VariableDefinition,
|
||||||
#[graphql(name = "FRAGMENT_SPREAD")]
|
#[graphql(name = "FRAGMENT_SPREAD")]
|
||||||
FragmentSpread,
|
FragmentSpread,
|
||||||
#[graphql(name = "INLINE_FRAGMENT")]
|
#[graphql(name = "INLINE_FRAGMENT")]
|
||||||
|
@ -588,27 +590,28 @@ where
|
||||||
|
|
||||||
impl fmt::Display for DirectiveLocation {
|
impl fmt::Display for DirectiveLocation {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.write_str(match *self {
|
f.write_str(match self {
|
||||||
DirectiveLocation::Query => "query",
|
Self::Query => "query",
|
||||||
DirectiveLocation::Mutation => "mutation",
|
Self::Mutation => "mutation",
|
||||||
DirectiveLocation::Subscription => "subscription",
|
Self::Subscription => "subscription",
|
||||||
DirectiveLocation::Field => "field",
|
Self::Field => "field",
|
||||||
DirectiveLocation::FieldDefinition => "field definition",
|
Self::FieldDefinition => "field definition",
|
||||||
DirectiveLocation::FragmentDefinition => "fragment definition",
|
Self::FragmentDefinition => "fragment definition",
|
||||||
DirectiveLocation::FragmentSpread => "fragment spread",
|
Self::FragmentSpread => "fragment spread",
|
||||||
DirectiveLocation::InlineFragment => "inline fragment",
|
Self::InlineFragment => "inline fragment",
|
||||||
DirectiveLocation::Scalar => "scalar",
|
Self::VariableDefinition => "variable definition",
|
||||||
DirectiveLocation::EnumValue => "enum value",
|
Self::Scalar => "scalar",
|
||||||
|
Self::EnumValue => "enum value",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S> fmt::Display for TypeType<'a, S> {
|
impl<'a, S> fmt::Display for TypeType<'a, S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match self {
|
||||||
TypeType::Concrete(t) => f.write_str(t.name().unwrap()),
|
Self::Concrete(t) => f.write_str(t.name().unwrap()),
|
||||||
TypeType::List(ref i, _) => write!(f, "[{}]", i),
|
Self::List(i, _) => write!(f, "[{}]", i),
|
||||||
TypeType::NonNull(ref i) => write!(f, "{}!", i),
|
Self::NonNull(i) => write!(f, "{}!", i),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1056,6 +1056,12 @@ pub(crate) fn schema_introspection_result() -> Value {
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "VARIABLE_DEFINITION",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "FRAGMENT_SPREAD",
|
"name": "FRAGMENT_SPREAD",
|
||||||
"description": null,
|
"description": null,
|
||||||
|
@ -2387,6 +2393,11 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> Value {
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "VARIABLE_DEFINITION",
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "FRAGMENT_SPREAD",
|
"name": "FRAGMENT_SPREAD",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType},
|
ast::{
|
||||||
|
Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType,
|
||||||
|
VariableDefinition,
|
||||||
|
},
|
||||||
parser::Spanning,
|
parser::Spanning,
|
||||||
schema::model::DirectiveLocation,
|
schema::model::DirectiveLocation,
|
||||||
validation::{ValidatorContext, Visitor},
|
validation::{ValidatorContext, Visitor},
|
||||||
|
@ -106,6 +109,24 @@ where
|
||||||
assert_eq!(top, Some(DirectiveLocation::InlineFragment));
|
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(
|
fn enter_directive(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut ValidatorContext<'a, S>,
|
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]
|
#[test]
|
||||||
fn with_many_unknown_directives() {
|
fn with_many_unknown_directives() {
|
||||||
expect_fails_rule::<_, _, DefaultScalarValue>(
|
expect_fails_rule::<_, _, DefaultScalarValue>(
|
||||||
|
|
|
@ -141,6 +141,19 @@ fn visit_variable_definitions<'a, S, V>(
|
||||||
visit_input_value(v, ctx, default_value);
|
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);
|
v.exit_variable_definition(ctx, def);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue