Skip to content

Commit eb83b60

Browse files
authored
Support directives on variables definitions (#1005, #1000)
1 parent 18b10af commit eb83b60

File tree

7 files changed

+96
-16
lines changed

7 files changed

+96
-16
lines changed

juniper/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- 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))
2424
- Support `isRepeatable` field on directives. ([#1003](https://github.com/graphql-rust/juniper/pull/1003), [#1000](https://github.com/graphql-rust/juniper/pull/1000))
2525
- 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))
26+
- Support directives on variables definitions. ([#1005](https://github.com/graphql-rust/juniper/pull/1005))
2627

2728
## Fixes
2829

juniper/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub enum InputValue<S = DefaultScalarValue> {
4949
pub struct VariableDefinition<'a, S> {
5050
pub var_type: Spanning<Type<'a>>,
5151
pub default_value: Option<Spanning<InputValue<S>>>,
52+
pub directives: Option<Vec<Spanning<Directive<'a, S>>>>,
5253
}
5354

5455
#[derive(Clone, PartialEq, Debug)]

juniper/src/parser/document.rs

+3
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,8 @@ where
451451
None
452452
};
453453

454+
let directives = parse_directives(parser, schema)?;
455+
454456
Ok(Spanning::start_end(
455457
&start_pos,
456458
&default_value
@@ -462,6 +464,7 @@ where
462464
VariableDefinition {
463465
var_type,
464466
default_value,
467+
directives: directives.map(|s| s.item),
465468
},
466469
),
467470
))

juniper/src/schema/model.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ pub enum DirectiveLocation {
8787
FragmentDefinition,
8888
#[graphql(name = "FIELD_DEFINITION")]
8989
FieldDefinition,
90+
#[graphql(name = "VARIABLE_DEFINITION")]
91+
VariableDefinition,
9092
#[graphql(name = "FRAGMENT_SPREAD")]
9193
FragmentSpread,
9294
#[graphql(name = "INLINE_FRAGMENT")]
@@ -588,27 +590,28 @@ where
588590

589591
impl fmt::Display for DirectiveLocation {
590592
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591-
f.write_str(match *self {
592-
DirectiveLocation::Query => "query",
593-
DirectiveLocation::Mutation => "mutation",
594-
DirectiveLocation::Subscription => "subscription",
595-
DirectiveLocation::Field => "field",
596-
DirectiveLocation::FieldDefinition => "field definition",
597-
DirectiveLocation::FragmentDefinition => "fragment definition",
598-
DirectiveLocation::FragmentSpread => "fragment spread",
599-
DirectiveLocation::InlineFragment => "inline fragment",
600-
DirectiveLocation::Scalar => "scalar",
601-
DirectiveLocation::EnumValue => "enum value",
593+
f.write_str(match self {
594+
Self::Query => "query",
595+
Self::Mutation => "mutation",
596+
Self::Subscription => "subscription",
597+
Self::Field => "field",
598+
Self::FieldDefinition => "field definition",
599+
Self::FragmentDefinition => "fragment definition",
600+
Self::FragmentSpread => "fragment spread",
601+
Self::InlineFragment => "inline fragment",
602+
Self::VariableDefinition => "variable definition",
603+
Self::Scalar => "scalar",
604+
Self::EnumValue => "enum value",
602605
})
603606
}
604607
}
605608

606609
impl<'a, S> fmt::Display for TypeType<'a, S> {
607610
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608-
match *self {
609-
TypeType::Concrete(t) => f.write_str(t.name().unwrap()),
610-
TypeType::List(ref i, _) => write!(f, "[{}]", i),
611-
TypeType::NonNull(ref i) => write!(f, "{}!", i),
611+
match self {
612+
Self::Concrete(t) => f.write_str(t.name().unwrap()),
613+
Self::List(i, _) => write!(f, "[{}]", i),
614+
Self::NonNull(i) => write!(f, "{}!", i),
612615
}
613616
}
614617
}

juniper/src/tests/schema_introspection.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,12 @@ pub(crate) fn schema_introspection_result() -> Value {
10561056
"isDeprecated": false,
10571057
"deprecationReason": null
10581058
},
1059+
{
1060+
"name": "VARIABLE_DEFINITION",
1061+
"description": null,
1062+
"isDeprecated": false,
1063+
"deprecationReason": null
1064+
},
10591065
{
10601066
"name": "FRAGMENT_SPREAD",
10611067
"description": null,
@@ -2387,6 +2393,11 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> Value {
23872393
"isDeprecated": false,
23882394
"deprecationReason": null
23892395
},
2396+
{
2397+
"name": "VARIABLE_DEFINITION",
2398+
"isDeprecated": false,
2399+
"deprecationReason": null
2400+
},
23902401
{
23912402
"name": "FRAGMENT_SPREAD",
23922403
"isDeprecated": false,

juniper/src/validation/rules/known_directives.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::{
2-
ast::{Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType},
2+
ast::{
3+
Directive, Field, Fragment, FragmentSpread, InlineFragment, Operation, OperationType,
4+
VariableDefinition,
5+
},
36
parser::Spanning,
47
schema::model::DirectiveLocation,
58
validation::{ValidatorContext, Visitor},
@@ -106,6 +109,24 @@ where
106109
assert_eq!(top, Some(DirectiveLocation::InlineFragment));
107110
}
108111

112+
fn enter_variable_definition(
113+
&mut self,
114+
_: &mut ValidatorContext<'a, S>,
115+
_: &'a (Spanning<&'a str>, VariableDefinition<S>),
116+
) {
117+
self.location_stack
118+
.push(DirectiveLocation::VariableDefinition);
119+
}
120+
121+
fn exit_variable_definition(
122+
&mut self,
123+
_: &mut ValidatorContext<'a, S>,
124+
_: &'a (Spanning<&'a str>, VariableDefinition<S>),
125+
) {
126+
let top = self.location_stack.pop();
127+
assert_eq!(top, Some(DirectiveLocation::VariableDefinition));
128+
}
129+
109130
fn enter_directive(
110131
&mut self,
111132
ctx: &mut ValidatorContext<'a, S>,
@@ -206,6 +227,33 @@ mod tests {
206227
);
207228
}
208229

230+
#[test]
231+
fn with_unknown_directive_on_var_definition() {
232+
expect_fails_rule::<_, _, DefaultScalarValue>(
233+
factory,
234+
r#"query Foo(
235+
$var1: Int = 1 @skip(if: true) @unknown,
236+
$var2: String @deprecated
237+
) {
238+
name
239+
}"#,
240+
&[
241+
RuleError::new(
242+
&misplaced_error_message("skip", &DirectiveLocation::VariableDefinition),
243+
&[SourcePosition::new(42, 1, 31)],
244+
),
245+
RuleError::new(
246+
&unknown_error_message("unknown"),
247+
&[SourcePosition::new(58, 1, 47)],
248+
),
249+
RuleError::new(
250+
&misplaced_error_message("deprecated", &DirectiveLocation::VariableDefinition),
251+
&[SourcePosition::new(98, 2, 30)],
252+
),
253+
],
254+
);
255+
}
256+
209257
#[test]
210258
fn with_many_unknown_directives() {
211259
expect_fails_rule::<_, _, DefaultScalarValue>(

juniper/src/validation/visitor.rs

+13
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ fn visit_variable_definitions<'a, S, V>(
141141
visit_input_value(v, ctx, default_value);
142142
}
143143

144+
if let Some(dirs) = &def.1.directives {
145+
for directive in dirs {
146+
let directive_arguments = ctx
147+
.schema
148+
.directive_by_name(directive.item.name.item)
149+
.map(|d| &d.arguments);
150+
151+
v.enter_directive(ctx, directive);
152+
visit_arguments(v, ctx, directive_arguments, &directive.item.arguments);
153+
v.exit_directive(ctx, directive);
154+
}
155+
}
156+
144157
v.exit_variable_definition(ctx, def);
145158
})
146159
}

0 commit comments

Comments
 (0)