Skip to content

Commit 98b662c

Browse files
committed
Accept explicit null input values in queries
Explicit `null` values are valid for nullable input values. See <https://facebook.github.io/graphql/#sec-Types.Non-Null>. Fixes #23
1 parent 907d78d commit 98b662c

File tree

7 files changed

+52
-4
lines changed

7 files changed

+52
-4
lines changed

src/executor_tests/variables.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,17 @@ fn allow_nullable_inputs_to_be_omitted_in_variable() {
338338
});
339339
}
340340

341+
#[test]
342+
fn allow_nullable_inputs_to_be_explicitly_null() {
343+
run_query(
344+
r#"{ fieldWithNullableStringInput(input: null) }"#,
345+
|result| {
346+
assert_eq!(
347+
result.get("fieldWithNullableStringInput"),
348+
Some(&Value::string(r#"None"#)));
349+
});
350+
}
351+
341352
#[test]
342353
fn allow_nullable_inputs_to_be_set_to_null_in_variable() {
343354
run_variable_query(

src/parser/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn parse_value_literal<'a>(parser: &mut Parser<'a>, is_const: bool) -> Parse
2424
Spanning { item: Token::Name("false"), .. } =>
2525
Ok(parser.next().map(|_| InputValue::boolean(false))),
2626
Spanning { item: Token::Name("null"), .. } =>
27-
Err(parser.next().map(ParseError::UnexpectedToken)),
27+
Ok(parser.next().map(|_| InputValue::null())),
2828
Spanning { item: Token::Name(name), .. } =>
2929
Ok(parser.next().map(|_| InputValue::enum_value(name.to_owned()))),
3030
_ => Err(parser.next().map(ParseError::UnexpectedToken)),

src/types/utilities.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn is_valid_literal_value(schema: &SchemaType, arg_type: &TypeType, arg_valu
2121
}
2222
TypeType::Concrete(t) => {
2323
match *arg_value {
24-
ref v @ InputValue::Null |
24+
InputValue::Null => true,
2525
ref v @ InputValue::Int(_) |
2626
ref v @ InputValue::Float(_) |
2727
ref v @ InputValue::String(_) |

src/validation/multi_visitor.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ impl<'a> Visitor<'a> for MultiVisitor<'a> {
9595
self.visit_all(|v| v.exit_inline_fragment(ctx, f));
9696
}
9797

98+
fn enter_null_value(&mut self, ctx: &mut ValidatorContext<'a>, n: Spanning<()>) {
99+
self.visit_all(|v| v.enter_null_value(ctx, n.clone()));
100+
}
101+
fn exit_null_value(&mut self, ctx: &mut ValidatorContext<'a>, n: Spanning<()>) {
102+
self.visit_all(|v| v.exit_null_value(ctx, n.clone()));
103+
}
104+
98105
fn enter_int_value(&mut self, ctx: &mut ValidatorContext<'a>, i: Spanning<i64>) {
99106
self.visit_all(|v| v.enter_int_value(ctx, i.clone()));
100107
}

src/validation/rules/arguments_of_correct_type.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,33 @@ mod tests {
6464
use parser::SourcePosition;
6565
use validation::{RuleError, expect_passes_rule, expect_fails_rule};
6666

67+
#[test]
68+
fn good_null_value() {
69+
expect_passes_rule(factory, r#"
70+
{
71+
complicatedArgs {
72+
intArgField(intArg: null)
73+
}
74+
}
75+
"#);
76+
}
77+
78+
#[test]
79+
fn null_into_int() {
80+
expect_fails_rule(factory, r#"
81+
{
82+
complicatedArgs {
83+
nonNullIntArgField(nonNullIntArg: null)
84+
}
85+
}
86+
"#,
87+
&[
88+
RuleError::new(&error_message("nonNullIntArg", "Int!"), &[
89+
SourcePosition::new(97, 3, 50),
90+
])
91+
]);
92+
}
93+
6794
#[test]
6895
fn good_int_value() {
6996
expect_passes_rule(factory, r#"

src/validation/traits.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub trait Visitor<'a> {
3636
fn enter_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
3737
fn exit_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
3838

39+
fn enter_null_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<()>) {}
40+
fn exit_null_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<()>) {}
41+
3942
fn enter_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
4043
fn exit_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
4144

src/validation/visitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ fn enter_input_value<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorContext<'
226226
let end = &input_value.end;
227227

228228
match input_value.item {
229-
Null => panic!("null values can't appear in the AST"),
229+
Null => v.enter_null_value(ctx, Spanning::start_end(start, end, ())),
230230
Int(ref i) => v.enter_int_value(ctx, Spanning::start_end(start, end, *i)),
231231
Float(ref f) => v.enter_float_value(ctx, Spanning::start_end(start, end, *f)),
232232
String(ref s) => v.enter_string_value(ctx, Spanning::start_end(start, end, s)),
@@ -245,7 +245,7 @@ fn exit_input_value<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorContext<'a
245245
let end = &input_value.end;
246246

247247
match input_value.item {
248-
Null => panic!("null values can't appear in the AST"),
248+
Null => v.exit_null_value(ctx, Spanning::start_end(start, end, ())),
249249
Int(ref i) => v.exit_int_value(ctx, Spanning::start_end(start, end, *i)),
250250
Float(ref f) => v.exit_float_value(ctx, Spanning::start_end(start, end, *f)),
251251
String(ref s) => v.exit_string_value(ctx, Spanning::start_end(start, end, s)),

0 commit comments

Comments
 (0)