From 0ea61fa4936d62d9bdf0ef5344cc719b66575a3e Mon Sep 17 00:00:00 2001 From: Magnus Hallin <mhallin@fastmail.com> Date: Sat, 12 Nov 2016 22:52:34 +0100 Subject: [PATCH] Add interface and union tests --- src/executor_tests/interfaces_unions.rs | 221 ++++++++++++++++++++++++ src/executor_tests/mod.rs | 1 + src/macros/interface.rs | 13 ++ 3 files changed, 235 insertions(+) create mode 100644 src/executor_tests/interfaces_unions.rs diff --git a/src/executor_tests/interfaces_unions.rs b/src/executor_tests/interfaces_unions.rs new file mode 100644 index 00000000..b840787d --- /dev/null +++ b/src/executor_tests/interfaces_unions.rs @@ -0,0 +1,221 @@ +mod interface { + use value::Value; + use schema::model::RootNode; + + trait Pet { + fn name(&self) -> &str; + + fn as_dog(&self) -> Option<&Dog> { None } + fn as_cat(&self) -> Option<&Cat> { None } + } + + graphql_interface!(<'a> &'a Pet: () as "Pet" |&self| { + field name() -> &str { self.name() } + + instance_resolvers: |&_| { + &Dog => self.as_dog(), + &Cat => self.as_cat(), + } + }); + + struct Dog { + name: String, + woofs: bool, + } + + impl Pet for Dog { + fn name(&self) -> &str { &self.name } + fn as_dog(&self) -> Option<&Dog> { Some(self) } + } + + graphql_object!(Dog: () |&self| { + field name() -> &str { &self.name } + field woofs() -> bool { self.woofs } + + interfaces: [&Pet] + }); + + struct Cat { + name: String, + meows: bool, + } + + impl Pet for Cat { + fn name(&self) -> &str { &self.name } + fn as_cat(&self) -> Option<&Cat> { Some(self) } + } + + graphql_object!(Cat: () |&self| { + field name() -> &str { &self.name } + field meows() -> bool { self.meows } + + interfaces: [&Pet] + }); + + struct Schema { + pets: Vec<Box<Pet>>, + } + + graphql_object!(Schema: () |&self| { + field pets() -> Vec<&Pet> { + self.pets.iter().map(|p| p.as_ref()).collect() + } + }); + + #[test] + fn test() { + let schema = RootNode::new( + Schema { + pets: vec![ + Box::new(Dog { name: "Odie".to_owned(), woofs: true }), + Box::new(Cat { name: "Garfield".to_owned(), meows: false }), + ], + }, + ()); + let doc = r" + { + pets { + name + ... on Dog { + woofs + } + ... on Cat { + meows + } + } + }"; + + let vars = vec![ + ].into_iter().collect(); + + let (result, errs) = ::execute(doc, None, &schema, &vars, &()) + .expect("Execution failed"); + + assert_eq!(errs, []); + + println!("Result: {:?}", result); + + assert_eq!( + result, + Value::object(vec![ + ("pets", Value::list(vec![ + Value::object(vec![ + ("name", Value::string("Odie")), + ("woofs", Value::boolean(true)), + ].into_iter().collect()), + Value::object(vec![ + ("name", Value::string("Garfield")), + ("meows", Value::boolean(false)), + ].into_iter().collect()), + ])), + ].into_iter().collect())); + } +} + + + + +mod union { + use value::Value; + use schema::model::RootNode; + + trait Pet { + fn as_dog(&self) -> Option<&Dog> { None } + fn as_cat(&self) -> Option<&Cat> { None } + } + + graphql_union!(<'a> &'a Pet: () as "Pet" |&self| { + instance_resolvers: |&_| { + &Dog => self.as_dog(), + &Cat => self.as_cat(), + } + }); + + struct Dog { + name: String, + woofs: bool, + } + + impl Pet for Dog { + fn as_dog(&self) -> Option<&Dog> { Some(self) } + } + + graphql_object!(Dog: () |&self| { + field name() -> &str { &self.name } + field woofs() -> bool { self.woofs } + }); + + struct Cat { + name: String, + meows: bool, + } + + impl Pet for Cat { + fn as_cat(&self) -> Option<&Cat> { Some(self) } + } + + graphql_object!(Cat: () |&self| { + field name() -> &str { &self.name } + field meows() -> bool { self.meows } + }); + + struct Schema { + pets: Vec<Box<Pet>>, + } + + graphql_object!(Schema: () |&self| { + field pets() -> Vec<&Pet> { + self.pets.iter().map(|p| p.as_ref()).collect() + } + }); + + #[test] + fn test() { + let schema = RootNode::new( + Schema { + pets: vec![ + Box::new(Dog { name: "Odie".to_owned(), woofs: true }), + Box::new(Cat { name: "Garfield".to_owned(), meows: false }), + ], + }, + ()); + let doc = r" + { + pets { + ... on Dog { + name + woofs + } + ... on Cat { + name + meows + } + } + }"; + + let vars = vec![ + ].into_iter().collect(); + + let (result, errs) = ::execute(doc, None, &schema, &vars, &()) + .expect("Execution failed"); + + assert_eq!(errs, []); + + println!("Result: {:?}", result); + + assert_eq!( + result, + Value::object(vec![ + ("pets", Value::list(vec![ + Value::object(vec![ + ("name", Value::string("Odie")), + ("woofs", Value::boolean(true)), + ].into_iter().collect()), + Value::object(vec![ + ("name", Value::string("Garfield")), + ("meows", Value::boolean(false)), + ].into_iter().collect()), + ])), + ].into_iter().collect())); + } +} diff --git a/src/executor_tests/mod.rs b/src/executor_tests/mod.rs index 33440ba8..bf962966 100644 --- a/src/executor_tests/mod.rs +++ b/src/executor_tests/mod.rs @@ -3,3 +3,4 @@ mod variables; mod enums; mod directives; mod executor; +mod interfaces_unions; diff --git a/src/macros/interface.rs b/src/macros/interface.rs index be120a6a..2fddfbe6 100644 --- a/src/macros/interface.rs +++ b/src/macros/interface.rs @@ -169,6 +169,19 @@ 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 : | $ctxtvar:pat | { $( $srctype:ty => $resolver:expr ),* $(,)* } $( $rest:tt )* + ) => { + $( + let _ = $reg.get_type::<$srctype>(); + )* + + graphql_interface!(@gather_meta, ($reg, $acc, $descr), $( $rest )*) + }; + // instance_resolvers: | <ctxtvar> | [...] ( @ concrete_type_name,