Merge pull request #26 from zaeleus/explicit-null
Accept explicit null input values in queries
This commit is contained in:
commit
40cc76d2b9
7 changed files with 52 additions and 4 deletions
src
executor_tests
parser
types
validation
|
@ -338,6 +338,17 @@ fn allow_nullable_inputs_to_be_omitted_in_variable() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn allow_nullable_inputs_to_be_explicitly_null() {
|
||||||
|
run_query(
|
||||||
|
r#"{ fieldWithNullableStringInput(input: null) }"#,
|
||||||
|
|result| {
|
||||||
|
assert_eq!(
|
||||||
|
result.get("fieldWithNullableStringInput"),
|
||||||
|
Some(&Value::string(r#"None"#)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn allow_nullable_inputs_to_be_set_to_null_in_variable() {
|
fn allow_nullable_inputs_to_be_set_to_null_in_variable() {
|
||||||
run_variable_query(
|
run_variable_query(
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn parse_value_literal<'a>(parser: &mut Parser<'a>, is_const: bool) -> Parse
|
||||||
Spanning { item: Token::Name("false"), .. } =>
|
Spanning { item: Token::Name("false"), .. } =>
|
||||||
Ok(parser.next().map(|_| InputValue::boolean(false))),
|
Ok(parser.next().map(|_| InputValue::boolean(false))),
|
||||||
Spanning { item: Token::Name("null"), .. } =>
|
Spanning { item: Token::Name("null"), .. } =>
|
||||||
Err(parser.next().map(ParseError::UnexpectedToken)),
|
Ok(parser.next().map(|_| InputValue::null())),
|
||||||
Spanning { item: Token::Name(name), .. } =>
|
Spanning { item: Token::Name(name), .. } =>
|
||||||
Ok(parser.next().map(|_| InputValue::enum_value(name.to_owned()))),
|
Ok(parser.next().map(|_| InputValue::enum_value(name.to_owned()))),
|
||||||
_ => Err(parser.next().map(ParseError::UnexpectedToken)),
|
_ => Err(parser.next().map(ParseError::UnexpectedToken)),
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub fn is_valid_literal_value(schema: &SchemaType, arg_type: &TypeType, arg_valu
|
||||||
}
|
}
|
||||||
|
|
||||||
match *arg_value {
|
match *arg_value {
|
||||||
ref v @ InputValue::Null |
|
InputValue::Null => true,
|
||||||
ref v @ InputValue::Int(_) |
|
ref v @ InputValue::Int(_) |
|
||||||
ref v @ InputValue::Float(_) |
|
ref v @ InputValue::Float(_) |
|
||||||
ref v @ InputValue::String(_) |
|
ref v @ InputValue::String(_) |
|
||||||
|
|
|
@ -95,6 +95,13 @@ impl<'a> Visitor<'a> for MultiVisitor<'a> {
|
||||||
self.visit_all(|v| v.exit_inline_fragment(ctx, f));
|
self.visit_all(|v| v.exit_inline_fragment(ctx, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enter_null_value(&mut self, ctx: &mut ValidatorContext<'a>, n: Spanning<()>) {
|
||||||
|
self.visit_all(|v| v.enter_null_value(ctx, n.clone()));
|
||||||
|
}
|
||||||
|
fn exit_null_value(&mut self, ctx: &mut ValidatorContext<'a>, n: Spanning<()>) {
|
||||||
|
self.visit_all(|v| v.exit_null_value(ctx, n.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
fn enter_int_value(&mut self, ctx: &mut ValidatorContext<'a>, i: Spanning<i64>) {
|
fn enter_int_value(&mut self, ctx: &mut ValidatorContext<'a>, i: Spanning<i64>) {
|
||||||
self.visit_all(|v| v.enter_int_value(ctx, i.clone()));
|
self.visit_all(|v| v.enter_int_value(ctx, i.clone()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,33 @@ mod tests {
|
||||||
use parser::SourcePosition;
|
use parser::SourcePosition;
|
||||||
use validation::{RuleError, expect_passes_rule, expect_fails_rule};
|
use validation::{RuleError, expect_passes_rule, expect_fails_rule};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn good_null_value() {
|
||||||
|
expect_passes_rule(factory, r#"
|
||||||
|
{
|
||||||
|
complicatedArgs {
|
||||||
|
intArgField(intArg: null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn null_into_int() {
|
||||||
|
expect_fails_rule(factory, r#"
|
||||||
|
{
|
||||||
|
complicatedArgs {
|
||||||
|
nonNullIntArgField(nonNullIntArg: null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
&[
|
||||||
|
RuleError::new(&error_message("nonNullIntArg", "Int!"), &[
|
||||||
|
SourcePosition::new(97, 3, 50),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn good_int_value() {
|
fn good_int_value() {
|
||||||
expect_passes_rule(factory, r#"
|
expect_passes_rule(factory, r#"
|
||||||
|
|
|
@ -36,6 +36,9 @@ pub trait Visitor<'a> {
|
||||||
fn enter_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
|
fn enter_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
|
||||||
fn exit_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
|
fn exit_inline_fragment(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<InlineFragment>) {}
|
||||||
|
|
||||||
|
fn enter_null_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<()>) {}
|
||||||
|
fn exit_null_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<()>) {}
|
||||||
|
|
||||||
fn enter_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
|
fn enter_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
|
||||||
fn exit_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
|
fn exit_int_value(&mut self, _: &mut ValidatorContext<'a>, _: Spanning<i64>) {}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ fn enter_input_value<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorContext<'
|
||||||
let end = &input_value.end;
|
let end = &input_value.end;
|
||||||
|
|
||||||
match input_value.item {
|
match input_value.item {
|
||||||
Null => panic!("null values can't appear in the AST"),
|
Null => v.enter_null_value(ctx, Spanning::start_end(start, end, ())),
|
||||||
Int(ref i) => v.enter_int_value(ctx, Spanning::start_end(start, end, *i)),
|
Int(ref i) => v.enter_int_value(ctx, Spanning::start_end(start, end, *i)),
|
||||||
Float(ref f) => v.enter_float_value(ctx, Spanning::start_end(start, end, *f)),
|
Float(ref f) => v.enter_float_value(ctx, Spanning::start_end(start, end, *f)),
|
||||||
String(ref s) => v.enter_string_value(ctx, Spanning::start_end(start, end, s)),
|
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
|
||||||
let end = &input_value.end;
|
let end = &input_value.end;
|
||||||
|
|
||||||
match input_value.item {
|
match input_value.item {
|
||||||
Null => panic!("null values can't appear in the AST"),
|
Null => v.exit_null_value(ctx, Spanning::start_end(start, end, ())),
|
||||||
Int(ref i) => v.exit_int_value(ctx, Spanning::start_end(start, end, *i)),
|
Int(ref i) => v.exit_int_value(ctx, Spanning::start_end(start, end, *i)),
|
||||||
Float(ref f) => v.exit_float_value(ctx, Spanning::start_end(start, end, *f)),
|
Float(ref f) => v.exit_float_value(ctx, Spanning::start_end(start, end, *f)),
|
||||||
String(ref s) => v.exit_string_value(ctx, Spanning::start_end(start, end, s)),
|
String(ref s) => v.exit_string_value(ctx, Spanning::start_end(start, end, s)),
|
||||||
|
|
Loading…
Add table
Reference in a new issue