use async_graphql::*; #[tokio::test] pub async fn test_interface_simple_object() { #[derive(SimpleObject)] struct MyObj { id: i32, title: String, } #[derive(Interface)] #[graphql(field(name = "id", ty = "&i32"))] enum Node { MyObj(MyObj), } struct Query; #[Object] impl Query { async fn node(&self) -> Node { MyObj { id: 33, title: "haha".to_string(), } .into() } } let query = r#"{ node { ... on Node { id } } }"#; let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "node": { "id": 33, } }) ); } #[tokio::test] pub async fn test_interface_simple_object2() { #[derive(SimpleObject)] struct MyObj { id: i32, title: String, } #[derive(Interface)] #[graphql(field(name = "id", ty = "&i32"))] enum Node { MyObj(MyObj), } struct Query; #[Object] impl Query { async fn node(&self) -> Node { MyObj { id: 33, title: "haha".to_string(), } .into() } } let query = r#"{ node { ... on Node { id } } }"#; let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "node": { "id": 33, } }) ); } #[tokio::test] pub async fn test_multiple_interfaces() { struct MyObj; #[Object] impl MyObj { async fn value_a(&self) -> i32 { 1 } async fn value_b(&self) -> i32 { 2 } async fn value_c(&self) -> i32 { 3 } } #[derive(Interface)] #[graphql(field(name = "value_a", ty = "i32"))] enum InterfaceA { MyObj(MyObj), } #[derive(Interface)] #[graphql(field(name = "value_b", ty = "i32"))] enum InterfaceB { MyObj(MyObj), } struct Query; #[Object] impl Query { async fn my_obj(&self) -> InterfaceB { MyObj.into() } } let schema = Schema::build(Query, EmptyMutation, EmptySubscription) .register_output_type::() // `InterfaceA` is not directly referenced, so manual registration is required. .finish(); let query = r#"{ myObj { ... on InterfaceA { valueA } ... on InterfaceB { valueB } ... on MyObj { valueC } } }"#; assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "myObj": { "valueA": 1, "valueB": 2, "valueC": 3, } }) ); } #[tokio::test] pub async fn test_multiple_objects_in_multiple_interfaces() { struct MyObjOne; #[Object] impl MyObjOne { async fn value_a(&self) -> i32 { 1 } async fn value_b(&self) -> i32 { 2 } async fn value_c(&self) -> i32 { 3 } } struct MyObjTwo; #[Object] impl MyObjTwo { async fn value_a(&self) -> i32 { 1 } } #[derive(Interface)] #[graphql(field(name = "value_a", ty = "i32"))] enum InterfaceA { MyObjOne(MyObjOne), MyObjTwo(MyObjTwo), } #[derive(Interface)] #[graphql(field(name = "value_b", ty = "i32"))] enum InterfaceB { MyObjOne(MyObjOne), } struct Query; #[Object] impl Query { async fn my_obj(&self) -> Vec { vec![MyObjOne.into(), MyObjTwo.into()] } } let schema = Schema::build(Query, EmptyMutation, EmptySubscription) .register_output_type::() // `InterfaceB` is not directly referenced, so manual registration is required. .finish(); let query = r#"{ myObj { ... on InterfaceA { valueA } ... on InterfaceB { valueB } ... on MyObjOne { valueC } } }"#; assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "myObj": [{ "valueA": 1, "valueB": 2, "valueC": 3, }, { "valueA": 1 }] }) ); } #[tokio::test] pub async fn test_interface_field_result() { struct MyObj; #[Object] impl MyObj { async fn value(&self) -> FieldResult { Ok(10) } } #[derive(Interface)] #[graphql(field(name = "value", ty = "i32"))] enum Node { MyObj(MyObj), } struct Query; #[Object] impl Query { async fn node(&self) -> Node { MyObj.into() } } let query = r#"{ node { ... on Node { value } } }"#; let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "node": { "value": 10, } }) ); } #[tokio::test] pub async fn test_interface_field_method() { struct A; #[Object] impl A { #[graphql(name = "created_at")] pub async fn created_at(&self) -> i32 { 1 } } struct B; #[Object] impl B { #[graphql(name = "created_at")] pub async fn created_at(&self) -> i32 { 2 } } #[derive(Interface)] #[graphql(field(name = "created_at", method = "created_at", ty = "i32"))] enum MyInterface { A(A), B(B), } struct Query; #[Object] impl Query { async fn test(&self) -> MyInterface { A.into() } } let query = "{ test { created_at } }"; let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "test": { "created_at": 1, } }) ); } #[tokio::test] pub async fn test_interface_implement_other_interface() { #[derive(Interface)] #[graphql(field(name = "id", ty = "ID"))] pub enum Entity { Company(Company), Organization(Organization), } #[derive(Interface)] #[graphql(field(name = "id", ty = "ID"))] pub enum Node { Entity(Entity), } pub struct Company {} #[Object] impl Company { pub async fn id(&self) -> ID { "88".into() } } pub struct Organization {} #[Object] impl Organization { pub async fn id(&self) -> ID { "99".into() } } struct Query; #[Object] impl Query { async fn company(&self) -> Node { Entity::Company(Company {}).into() } async fn organization(&self) -> Node { Entity::Organization(Organization {}).into() } } let query = r#" { company { id } organization { id } } "#; let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(query).await.into_result().unwrap().data, value!({ "company": { "id": "88", }, "organization": { "id": "99", } }) ); } #[tokio::test] pub async fn test_issue_330() { #[derive(Interface)] #[graphql(field( desc = "The code represented as a number.", name = "number", ty = "String" ))] pub enum Code { Barcode(Barcode), Qrcode(Qrcode), } pub struct Barcode(String); #[Object] impl Barcode { pub async fn number(&self) -> String { format!("barcode:{}", self.0) } } pub struct Qrcode(String); #[Object] impl Qrcode { pub async fn number(&self) -> String { format!("qrcode:{}", self.0) } } #[derive(Interface)] #[graphql(field(desc = "The article number.", name = "number", ty = "Code"))] pub enum Article { Book(Book), } pub struct Book { code: String, } #[Object] impl Book { pub async fn number(&self) -> Barcode { Barcode(self.code.clone()) } } struct Query; #[Object] impl Query { pub async fn book(&self) -> Article { Book { code: "123456".to_string(), } .into() } } let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema .execute("{ book { number { number } } }") .await .into_result() .unwrap() .data, value!({ "book": { "number": { "number": "barcode:123456" } } }) ); } #[tokio::test] pub async fn test_interface_with_oneof_object() { #[derive(SimpleObject, InputObject)] #[graphql(input_name = "MyObjAInput")] struct MyObjA { id: i32, title_a: String, } #[derive(SimpleObject, InputObject)] #[graphql(input_name = "MyObjBInput")] struct MyObjB { id: i32, title_b: String, } #[derive(OneofObject, Interface)] #[graphql(input_name = "NodeInput", field(name = "id", ty = "&i32"))] enum Node { MyObjA(MyObjA), MyObjB(MyObjB), } struct Query; #[Object] impl Query { async fn node(&self, input: Node) -> Node { input } } let schema = Schema::new(Query, EmptyMutation, EmptySubscription); let query_a = r#"{ node(input: { myObjA: { id: 10, titleA: "abc" } }) { id ... on MyObjA { titleA } ... on MyObjB { titleB } } }"#; assert_eq!( schema.execute(query_a).await.into_result().unwrap().data, value!({ "node": { "id": 10, "titleA": "abc", } }) ); let query_b = r#"{ node(input: { myObjB: { id: 10, titleB: "abc" } }) { id ... on MyObjA { titleA } ... on MyObjB { titleB } } }"#; assert_eq!( schema.execute(query_b).await.into_result().unwrap().data, value!({ "node": { "id": 10, "titleB": "abc", } }) ); }