Add field deprecation support and tests

This commit is contained in:
Magnus Hallin 2016-10-16 12:34:29 +02:00
parent 6cc124d075
commit 1295e42c58
5 changed files with 330 additions and 11 deletions

View file

@ -1,6 +1,31 @@
#[doc(hidden)]
#[macro_export]
macro_rules! __graphql__build_field_matches {
// field deprecated <reason> <name>(...) -> <type> as <description> { ... }
(
$resolveargs:tt,
( $( $acc:tt )* ),
field deprecated $_reason:tt $name:ident $args:tt -> $t:ty as $desc:tt $body:block $( $rest:tt )*
) => {
__graphql__build_field_matches!(
$resolveargs,
(($name; $args; $t; $body) $( $acc )*),
$( $rest )*);
};
// field deprecated <reason> <name>(...) -> <type> { ... }
(
$resolveargs:tt,
( $( $acc:tt )* ),
field deprecated $_reason:tt $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*
) => {
__graphql__build_field_matches!(
$resolveargs,
(($name; $args; $t; $body) $( $acc )*),
$( $rest )*);
};
// field <name>(...) -> <type> as <description> { ... }
(
$resolveargs:tt,
( $( $acc:tt )* ), field $name:ident $args:tt -> $t:ty as $desc:tt $body:block $( $rest:tt )*
@ -11,6 +36,7 @@ macro_rules! __graphql__build_field_matches {
$( $rest )*);
};
// field <name>(...) -> <type> { ... }
(
$resolveargs:tt,
( $( $acc:tt )* ), field $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*

View file

@ -88,6 +88,44 @@ macro_rules! graphql_interface {
( @as_item, $i:item) => { $i };
( @as_expr, $e:expr) => { $e };
// field deprecated <reason> <name>(...) -> <type> as <description> { ... }
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty as $desc:tt $body:block $( $rest:tt )*
) => {
$acc.push(__graphql__args!(
@apply_args,
$reg,
$reg.field_inside_result(
&$crate::to_snake_case(stringify!($name)),
Err("dummy".to_owned()) as $t)
.description($desc)
.deprecated($reason),
$args));
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*);
};
// field deprecated <reason> <name>(...) -> <type> { ... }
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*
) => {
$acc.push(__graphql__args!(
@apply_args,
$reg,
$reg.field_inside_result(
&$crate::to_snake_case(stringify!($name)),
Err("dummy".to_owned()) as $t)
.deprecated($reason),
$args));
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*);
};
// field <name>(...) -> <type> as <description> { ... }
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
@ -105,6 +143,7 @@ macro_rules! graphql_interface {
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*);
};
// field <name>(...) -> <type> { ... }
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
@ -121,6 +160,7 @@ macro_rules! graphql_interface {
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*);
};
// description: <description>
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
@ -131,16 +171,36 @@ macro_rules! graphql_interface {
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*)
};
// instance_resolvers: | <ctxtvar> | [...]
(
@gather_meta,
$reg:expr, $acc:expr, $descr:expr,
instance_resolvers: | $execvar:pat | $resolvers:tt $( $rest:tt )*
instance_resolvers: | $ctxtvar:pat | $resolvers:tt $( $rest:tt )*
) => {
graphql_interface!(@gather_meta, $reg, $acc, $descr, $( $rest )*)
};
( @gather_meta, $reg:expr, $acc:expr, $descr:expr, $(,)* ) => {};
// field deprecated <reason> <name>(...) -> <type> as <description> { ... }
(
@resolve_into_type,
$buildargs:tt,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty as $descr:tt $body:block $( $rest:tt )*
) => {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
};
// field deprecated <reason> <name>(...) -> <type> { ... }
(
@resolve_into_type,
$buildargs:tt,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*
) => {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
};
// field <name>(...) -> <type> as <description> { ... }
(
@resolve_into_type,
$buildargs:tt,
@ -149,6 +209,7 @@ macro_rules! graphql_interface {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
};
// field <name>(...) -> <type> { ... }
(
@resolve_into_type,
$buildargs:tt,
@ -157,6 +218,7 @@ macro_rules! graphql_interface {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
};
// description: <description>
(
@resolve_into_type,
$buildargs:tt, description : $value:tt $( $rest:tt )*
@ -164,13 +226,25 @@ macro_rules! graphql_interface {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
};
// field deprecated <reason> <name>(...) -> <type> as <description> { ... }
(
@resolve_into_type,
$buildargs:tt, interfaces : $value:tt $( $rest:tt )*
@concrete_type_name,
$buildargs:tt,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty as $descr:tt $body:block $( $rest:tt )*
) => {
graphql_interface!(@resolve_into_type, $buildargs, $( $rest )*)
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
// field deprecated <reason> <name>(...) -> <type> { ... }
(
@concrete_type_name,
$buildargs:tt,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*
) => {
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
// field <name>(...) -> <type> as <description> { ... }
(
@concrete_type_name,
$buildargs:tt,
@ -179,6 +253,7 @@ macro_rules! graphql_interface {
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
// field <name>(...) -> <type> { ... }
(
@concrete_type_name,
$buildargs:tt,
@ -187,6 +262,7 @@ macro_rules! graphql_interface {
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
// description: <description>
(
@concrete_type_name,
$buildargs:tt, description : $value:tt $( $rest:tt )*
@ -194,13 +270,7 @@ macro_rules! graphql_interface {
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
(
@concrete_type_name,
$buildargs:tt, interfaces : $value:tt $( $rest:tt )*
) => {
graphql_interface!(@concrete_type_name, $buildargs, $( $rest )*)
};
// instance_resolvers: | <ctxtvar> | [...]
(
@concrete_type_name,
($outname:tt, $ctxtarg:ident, $ctxttype:ty),
@ -225,6 +295,7 @@ macro_rules! graphql_interface {
()
};
// instance_resolvers: | <ctxtvar> |
(
@resolve_into_type,
($outname:tt, $typenamearg:ident, $execarg:ident, $ctxttype:ty),

View file

@ -239,6 +239,44 @@ macro_rules! graphql_object {
( @as_item, $i:item) => { $i };
( @as_expr, $e:expr) => { $e };
// field deprecated <reason> <name>(...) -> <type> as <description> { ... }
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty as $desc:tt $body:block $( $rest:tt )*
) => {
$acc.push(__graphql__args!(
@apply_args,
$reg,
$reg.field_inside_result(
&$crate::to_snake_case(stringify!($name)),
Err("dummy".to_owned()) as $t)
.description($desc)
.deprecated($reason),
$args));
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*);
};
// field deprecated <reason> <name>(...) -> <type> { ... }
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
field deprecated $reason:tt $name:ident $args:tt -> $t:ty $body:block $( $rest:tt )*
) => {
$acc.push(__graphql__args!(
@apply_args,
$reg,
$reg.field_inside_result(
&$crate::to_snake_case(stringify!($name)),
Err("dummy".to_owned()) as $t)
.deprecated($reason),
$args));
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*);
};
// field <name>(...) -> <type> as <description> { ... }
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
@ -256,6 +294,7 @@ macro_rules! graphql_object {
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*);
};
// field <name>(...) -> <type> { ... }
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
@ -272,6 +311,7 @@ macro_rules! graphql_object {
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*);
};
// description: <description>
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
@ -282,6 +322,7 @@ macro_rules! graphql_object {
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*)
};
// interfaces: [...]
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr,
@ -292,6 +333,7 @@ macro_rules! graphql_object {
graphql_object!(@gather_object_meta, $reg, $acc, $descr, $ifaces, $( $rest )*)
};
// base case
(
@gather_object_meta,
$reg:expr, $acc:expr, $descr:expr, $ifaces:expr, $(,)*

179
src/macros/tests/field.rs Normal file
View file

@ -0,0 +1,179 @@
use std::collections::HashMap;
use executor::FieldResult;
use value::Value;
use ast::InputValue;
use schema::model::RootNode;
struct Interface;
struct Root;
/*
Syntax to validate:
* Object vs. interface
* Description vs. no description
* Deprecated vs. not deprecated
*/
graphql_object!(Root: () as "Root" |&self| {
field simple() -> FieldResult<i64> { Ok(0) }
field description() -> FieldResult<i64> as "Field description" { Ok(0) }
field deprecated "Deprecation reason"
deprecated() -> FieldResult<i64> { Ok(0) }
field deprecated "Deprecation reason"
deprecated_descr() -> FieldResult<i64> as "Field description" { Ok(0) }
interfaces: [Interface]
});
graphql_interface!(Interface: () as "Interface" |&self| {
field simple() -> FieldResult<i64> { Ok(0) }
field description() -> FieldResult<i64> as "Field description" { Ok(0) }
field deprecated "Deprecation reason"
deprecated() -> FieldResult<i64> { Ok(0) }
field deprecated "Deprecation reason"
deprecated_descr() -> FieldResult<i64> as "Field description" { Ok(0) }
instance_resolvers: |&_| [
Some(Root {}),
]
});
fn run_field_info_query<F>(type_name: &str, field_name: &str, f: F)
where F: Fn(&HashMap<String, Value>) -> ()
{
let doc = r#"
query ($typeName: String!) {
__type(name: $typeName) {
fields(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
}
}
"#;
let schema = RootNode::new(Root {}, ());
let vars = vec![
("typeName".to_owned(), InputValue::string(type_name)),
].into_iter().collect();
let (result, errs) = ::execute(doc, None, &schema, &vars, &())
.expect("Execution failed");
assert_eq!(errs, []);
println!("Result: {:?}", result);
let type_info = result
.as_object_value().expect("Result is not an object")
.get("__type").expect("__type field missing")
.as_object_value().expect("__type field not an object value");
let fields = type_info
.get("fields").expect("fields field missing")
.as_list_value().expect("fields not a list");
let field = fields
.into_iter().filter(
|f| f.as_object_value().expect("Field not an object")
.get("name").expect("name field missing from field")
.as_string_value().expect("name is not a string")
== field_name)
.next().expect("Field not found")
.as_object_value().expect("Field is not an object");
println!("Field: {:?}", field);
f(field);
}
#[test]
fn introspect_object_field_simple() {
run_field_info_query("Root", "simple", |field| {
assert_eq!(field.get("name"), Some(&Value::string("simple")));
assert_eq!(field.get("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null()));
});
}
#[test]
fn introspect_interface_field_simple() {
run_field_info_query("Interface", "simple", |field| {
assert_eq!(field.get("name"), Some(&Value::string("simple")));
assert_eq!(field.get("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null()));
});
}
#[test]
fn introspect_object_field_description() {
run_field_info_query("Root", "description", |field| {
assert_eq!(field.get("name"), Some(&Value::string("description")));
assert_eq!(field.get("description"), Some(&Value::string("Field description")));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null()));
});
}
#[test]
fn introspect_interface_field_description() {
run_field_info_query("Interface", "description", |field| {
assert_eq!(field.get("name"), Some(&Value::string("description")));
assert_eq!(field.get("description"), Some(&Value::string("Field description")));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null()));
});
}
#[test]
fn introspect_object_field_deprecated() {
run_field_info_query("Root", "deprecated", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecated")));
assert_eq!(field.get("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!(field.get("deprecationReason"), Some(&Value::string("Deprecation reason")));
});
}
#[test]
fn introspect_interface_field_deprecated() {
run_field_info_query("Interface", "deprecated", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecated")));
assert_eq!(field.get("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!(field.get("deprecationReason"), Some(&Value::string("Deprecation reason")));
});
}
#[test]
fn introspect_object_field_deprecated_descr() {
run_field_info_query("Root", "deprecatedDescr", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecatedDescr")));
assert_eq!(field.get("description"), Some(&Value::string("Field description")));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!(field.get("deprecationReason"), Some(&Value::string("Deprecation reason")));
});
}
#[test]
fn introspect_interface_field_deprecated_descr() {
run_field_info_query("Interface", "deprecatedDescr", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecatedDescr")));
assert_eq!(field.get("description"), Some(&Value::string("Field description")));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!(field.get("deprecationReason"), Some(&Value::string("Deprecation reason")));
});
}

View file

@ -2,3 +2,4 @@ mod enums;
mod scalar;
#[allow(dead_code)] mod input_object;
mod args;
mod field;