Add support for default values in input objects
This commit is contained in:
parent
e0c6b03171
commit
0b07dbe99a
4 changed files with 165 additions and 13 deletions
|
@ -330,13 +330,34 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
|
|||
None => return Err(GraphQLError::UnknownOperationName),
|
||||
};
|
||||
|
||||
let default_variable_values = op.item.variable_definitions
|
||||
.map(|defs| defs.item.items.iter().filter_map(
|
||||
|&(ref name, ref def)| def.default_value.as_ref().map(
|
||||
|i| (name.item.to_owned(), i.item.clone())))
|
||||
.collect::<HashMap<String, InputValue>>());
|
||||
|
||||
let errors = RwLock::new(Vec::new());
|
||||
let value;
|
||||
|
||||
{
|
||||
let mut all_vars;
|
||||
let mut final_vars = variables;
|
||||
|
||||
if let Some(defaults) = default_variable_values {
|
||||
all_vars = variables.clone();
|
||||
|
||||
for (name, value) in defaults {
|
||||
if !all_vars.contains_key(&name) {
|
||||
all_vars.insert(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
final_vars = &all_vars;
|
||||
}
|
||||
|
||||
let executor = Executor {
|
||||
fragments: &fragments.iter().map(|f| (f.item.name.item, &f.item)).collect(),
|
||||
variables: variables,
|
||||
variables: final_vars,
|
||||
current_selection_set: Some(&op.item.selection_set[..]),
|
||||
schema: &root_node.schema,
|
||||
context: context,
|
||||
|
|
|
@ -57,6 +57,13 @@ graphql_input_object!(
|
|||
}
|
||||
);
|
||||
|
||||
graphql_input_object!(
|
||||
#[derive(Debug)]
|
||||
struct InputWithDefaults {
|
||||
a = 123: i64,
|
||||
}
|
||||
);
|
||||
|
||||
graphql_object!(TestType: () |&self| {
|
||||
field field_with_object_input(input: Option<TestInputObject>) -> String {
|
||||
format!("{:?}", input)
|
||||
|
@ -97,6 +104,10 @@ graphql_object!(TestType: () |&self| {
|
|||
field example_input(arg: ExampleInputObject) -> String {
|
||||
format!("a: {:?}, b: {:?}", arg.a, arg.b)
|
||||
}
|
||||
|
||||
field input_with_defaults(arg: InputWithDefaults) -> String {
|
||||
format!("a: {:?}", arg.a)
|
||||
}
|
||||
});
|
||||
|
||||
fn run_variable_query<F>(query: &str, vars: Variables, f: F)
|
||||
|
@ -891,3 +902,46 @@ fn does_not_allow_null_variable_for_required_field() {
|
|||
),
|
||||
]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_object_with_default_values() {
|
||||
run_query(
|
||||
r#"{ inputWithDefaults(arg: {a: 1}) }"#,
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get("inputWithDefaults"),
|
||||
Some(&Value::string(r#"a: 1"#)));
|
||||
});
|
||||
|
||||
run_variable_query(
|
||||
r#"query q($var: Int!) { inputWithDefaults(arg: {a: $var}) }"#,
|
||||
vec![
|
||||
("var".to_owned(), InputValue::int(1)),
|
||||
].into_iter().collect(),
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get("inputWithDefaults"),
|
||||
Some(&Value::string(r#"a: 1"#)));
|
||||
});
|
||||
|
||||
run_variable_query(
|
||||
r#"query q($var: Int = 1) { inputWithDefaults(arg: {a: $var}) }"#,
|
||||
vec![
|
||||
].into_iter().collect(),
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get("inputWithDefaults"),
|
||||
Some(&Value::string(r#"a: 1"#)));
|
||||
});
|
||||
|
||||
run_variable_query(
|
||||
r#"query q($var: Int = 1) { inputWithDefaults(arg: {a: $var}) }"#,
|
||||
vec![
|
||||
("var".to_owned(), InputValue::int(2)),
|
||||
].into_iter().collect(),
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get("inputWithDefaults"),
|
||||
Some(&Value::string(r#"a: 2"#)));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,17 +45,19 @@ macro_rules! graphql_input_object {
|
|||
(
|
||||
@generate_from_input_value,
|
||||
$name:tt, $var:tt,
|
||||
( $($field_name:ident : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
( $($field_name:ident $(= $default:tt)* : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
) => {
|
||||
Some($name {
|
||||
$( $field_name: {
|
||||
let n: String = $crate::to_camel_case(stringify!($field_name));
|
||||
let v: Option<&&$crate::InputValue> = $var.get(&n[..]);
|
||||
|
||||
if let Some(v) = v {
|
||||
$crate::FromInputValue::from(v).unwrap()
|
||||
} else {
|
||||
$crate::FromInputValue::from(&$crate::InputValue::null()).unwrap()
|
||||
println!("Found variable for {:?}: {:?} in {:?}", n, v, $var);
|
||||
|
||||
match v {
|
||||
$( Some(&&InputValue::Null) | None if true => $default, )*
|
||||
Some(v) => $crate::FromInputValue::from(v).unwrap(),
|
||||
_ => $crate::FromInputValue::from(&$crate::InputValue::null()).unwrap()
|
||||
}
|
||||
} ),*
|
||||
})
|
||||
|
@ -65,26 +67,53 @@ macro_rules! graphql_input_object {
|
|||
(
|
||||
@generate_struct_fields,
|
||||
( $($meta:tt)* ), ( $($pubmod:tt)* ), $name:tt,
|
||||
( $($field_name:ident : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
( $($field_name:ident $(= $default:tt)* : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
) => {
|
||||
$($meta)* $($pubmod)* struct $name {
|
||||
$( $field_name: $field_type, )*
|
||||
}
|
||||
};
|
||||
|
||||
// Generate the input field meta list, i.e. &[Argument].
|
||||
// Generate single field meta for field with default value
|
||||
(
|
||||
@generate_single_meta_field,
|
||||
$reg:tt,
|
||||
( $field_name:ident = $default:tt : $field_type:ty $(as $descr:tt)* )
|
||||
) => {
|
||||
graphql_input_object!(
|
||||
@apply_description,
|
||||
$($descr)*,
|
||||
$reg.arg_with_default::<$field_type>(
|
||||
&$crate::to_camel_case(stringify!($field_name)),
|
||||
&$default))
|
||||
};
|
||||
|
||||
// Generate single field meta for field without default value
|
||||
(
|
||||
@generate_single_meta_field,
|
||||
$reg:tt,
|
||||
( $field_name:ident : $field_type:ty $(as $descr:tt)* )
|
||||
) => {
|
||||
graphql_input_object!(
|
||||
@apply_description,
|
||||
$($descr)*,
|
||||
$reg.arg::<$field_type>(
|
||||
&$crate::to_camel_case(stringify!($field_name))))
|
||||
};
|
||||
|
||||
// Generate the input field meta list, i.e. &[Argument] for
|
||||
(
|
||||
@generate_meta_fields,
|
||||
$reg:tt,
|
||||
( $($field_name:ident : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
( $($field_name:ident $(= $default:tt)* : $field_type:ty $(as $descr:tt)* $(,)* ),* )
|
||||
) => {
|
||||
&[
|
||||
$(
|
||||
graphql_input_object!(
|
||||
@apply_description,
|
||||
$($descr)*,
|
||||
$reg.arg::<$field_type>(
|
||||
&$crate::to_camel_case(stringify!($field_name))))
|
||||
@generate_single_meta_field,
|
||||
$reg,
|
||||
( $field_name $(= $default)* : $field_type $(as $descr)* )
|
||||
)
|
||||
),*
|
||||
]
|
||||
};
|
||||
|
|
|
@ -78,6 +78,13 @@ graphql_input_object!(
|
|||
}
|
||||
);
|
||||
|
||||
graphql_input_object!(
|
||||
struct FieldWithDefaults {
|
||||
field_one = 123: i64,
|
||||
field_two = 456: i64 as "The second field",
|
||||
}
|
||||
);
|
||||
|
||||
graphql_object!(Root: () |&self| {
|
||||
field test_field(
|
||||
a1: DefaultName,
|
||||
|
@ -90,6 +97,7 @@ graphql_object!(Root: () |&self| {
|
|||
a8: PublicWithDescription,
|
||||
a9: NamedPublicWithDescription,
|
||||
a10: NamedPublic,
|
||||
a11: FieldWithDefaults,
|
||||
) -> i64 {
|
||||
0
|
||||
}
|
||||
|
@ -414,3 +422,43 @@ fn field_description_introspection() {
|
|||
].into_iter().collect())));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_with_defaults_introspection() {
|
||||
let doc = r#"
|
||||
{
|
||||
__type(name: "FieldWithDefaults") {
|
||||
name
|
||||
inputFields {
|
||||
name
|
||||
type {
|
||||
name
|
||||
}
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
run_type_info_query(doc, |type_info, fields| {
|
||||
assert_eq!(type_info.get("name"), Some(&Value::string("FieldWithDefaults")));
|
||||
|
||||
assert_eq!(fields.len(), 2);
|
||||
|
||||
assert!(fields.contains(&Value::object(vec![
|
||||
("name", Value::string("fieldOne")),
|
||||
("type", Value::object(vec![
|
||||
("name", Value::string("Int")),
|
||||
].into_iter().collect())),
|
||||
("defaultValue", Value::string("123")),
|
||||
].into_iter().collect())));
|
||||
|
||||
assert!(fields.contains(&Value::object(vec![
|
||||
("name", Value::string("fieldTwo")),
|
||||
("type", Value::object(vec![
|
||||
("name", Value::string("Int")),
|
||||
].into_iter().collect())),
|
||||
("defaultValue", Value::string("456")),
|
||||
].into_iter().collect())));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue