Skip to content

Commit

Permalink
Support directives on variables definitions (#1005, #1000)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilslv committed Dec 21, 2021
1 parent 18b10af commit eb83b60
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 16 deletions.
1 change: 1 addition & 0 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions juniper/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
3 changes: 3 additions & 0 deletions juniper/src/parser/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@ where
None
};

let directives = parse_directives(parser, schema)?;

Ok(Spanning::start_end(
&start_pos,
&default_value
Expand All @@ -462,6 +464,7 @@ where
VariableDefinition {
var_type,
default_value,
directives: directives.map(|s| s.item),
},
),
))
Expand Down
33 changes: 18 additions & 15 deletions juniper/src/schema/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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),
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions juniper/src/tests/schema_introspection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
50 changes: 49 additions & 1 deletion juniper/src/validation/rules/known_directives.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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>(
Expand Down
13 changes: 13 additions & 0 deletions juniper/src/validation/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})
}
Expand Down

0 comments on commit eb83b60

Please sign in to comment.