diff --git a/Cargo.toml b/Cargo.toml index 0204f579..9becf6bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-graphql" -version = "1.9.8" +version = "1.9.9" authors = ["sunli "] edition = "2018" description = "The GraphQL server library implemented by rust" @@ -18,7 +18,7 @@ default = ["bson", "uuid", "url", "chrono-tz", "validators"] validators = ["regex"] [dependencies] -async-graphql-derive = { path = "async-graphql-derive", version = "1.9.8" } +async-graphql-derive = { path = "async-graphql-derive", version = "1.9.9" } graphql-parser = "=0.2.3" anyhow = "1.0.26" thiserror = "1.0.11" diff --git a/async-graphql-actix-web/Cargo.toml b/async-graphql-actix-web/Cargo.toml index 579912c3..653775e3 100644 --- a/async-graphql-actix-web/Cargo.toml +++ b/async-graphql-actix-web/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-graphql-actix-web" -version = "1.0.8" +version = "1.0.9" authors = ["sunli "] edition = "2018" description = "async-graphql for actix-web" @@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"] categories = ["network-programming", "asynchronous"] [dependencies] -async-graphql = { path = "..", version = "1.9.8" } +async-graphql = { path = "..", version = "1.9.9" } actix-web = "2.0.0" actix-web-actors = "2.0.0" actix = "0.9.0" diff --git a/async-graphql-derive/Cargo.toml b/async-graphql-derive/Cargo.toml index 2c8d751b..027c18bb 100644 --- a/async-graphql-derive/Cargo.toml +++ b/async-graphql-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-graphql-derive" -version = "1.9.8" +version = "1.9.9" authors = ["sunli "] edition = "2018" description = "Macros for async-graphql" diff --git a/async-graphql-derive/src/interface.rs b/async-graphql-derive/src/interface.rs index 7a3e1eda..89344bec 100644 --- a/async-graphql-derive/src/interface.rs +++ b/async-graphql-derive/src/interface.rs @@ -223,7 +223,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result OutputType::Result(_, _) => { quote! { self.#method_name(#(#use_params),*).await. - map_err(|err| err.with_position(field.position))? + map_err(|err| err.into_error_with_path(field.position, ctx.path_node.as_ref().unwrap().to_json()))? } } }; diff --git a/async-graphql-warp/Cargo.toml b/async-graphql-warp/Cargo.toml index 0c8daa2c..519271b1 100644 --- a/async-graphql-warp/Cargo.toml +++ b/async-graphql-warp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-graphql-warp" -version = "1.0.9" +version = "1.0.10" authors = ["sunli "] edition = "2018" description = "async-graphql for warp" @@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"] categories = ["network-programming", "asynchronous"] [dependencies] -async-graphql = { path = "..", version = "1.9.8" } +async-graphql = { path = "..", version = "1.9.9" } warp = "0.2.2" futures = "0.3.0" bytes = "0.5.4" diff --git a/tests/interface.rs b/tests/interface.rs index 45f9229a..5581beb6 100644 --- a/tests/interface.rs +++ b/tests/interface.rs @@ -3,15 +3,15 @@ use async_graphql::*; #[async_std::test] pub async fn test_interface_simple_object() { #[async_graphql::SimpleObject] - pub struct MyObj { + struct MyObj { #[field] - pub id: i32, + id: i32, #[field] - pub title: String, + title: String, } #[async_graphql::Interface(field(name = "id", type = "i32"))] - pub struct Node(MyObj); + struct Node(MyObj); struct Query; @@ -50,15 +50,15 @@ pub async fn test_interface_simple_object() { #[async_std::test] pub async fn test_interface_simple_object2() { #[async_graphql::SimpleObject] - pub struct MyObj { + struct MyObj { #[field(ref)] - pub id: i32, + id: i32, #[field] - pub title: String, + title: String, } #[async_graphql::Interface(field(name = "id", type = "&i32"))] - pub struct Node(MyObj); + struct Node(MyObj); struct Query; @@ -163,81 +163,127 @@ pub async fn test_multiple_interfaces() { } #[async_std::test] -pub async fn test_multiple_objects_in_multiple_interfaces() { - struct MyObjOne; + pub async fn test_multiple_objects_in_multiple_interfaces() { + struct MyObjOne; + + #[async_graphql::Object] + impl MyObjOne { + #[field] + async fn value_a(&self) -> i32 { + 1 + } + + #[field] + async fn value_b(&self) -> i32 { + 2 + } + + #[field] + async fn value_c(&self) -> i32 { + 3 + } + } + + struct MyObjTwo; + + #[async_graphql::Object] + impl MyObjTwo { + #[field] + async fn value_a(&self) -> i32 { + 1 + } + } + + #[async_graphql::Interface(field(name = "value_a", type = "i32"))] + struct InterfaceA(MyObjOne, MyObjTwo); + + #[async_graphql::Interface(field(name = "value_b", type = "i32"))] + struct InterfaceB(MyObjOne); + + struct Query; + + #[Object] + impl Query { + #[field] + async fn my_obj(&self) -> Vec { + vec![MyObjOne.into(), MyObjTwo.into()] + } + } + + let schema = Schema::build(Query, EmptyMutation, EmptySubscription) + .register_type::() // `InterfaceA` is not directly referenced, so manual registration is required. + .finish(); + let query = format!( + r#"{{ + myObj {{ + ... on InterfaceA {{ + valueA + }} + ... on InterfaceB {{ + valueB + }} + ... on MyObjOne {{ + valueC + }} + }} + }}"# + ); + assert_eq!( + schema.execute(&query).await.unwrap().data, + serde_json::json!({ + "myObj": [{ + "valueA": 1, + "valueB": 2, + "valueC": 3, + }, { + "valueA": 1 + }] + }) + ); + } + +#[async_std::test] +pub async fn test_interface_field_result() { + struct MyObj; #[async_graphql::Object] - impl MyObjOne { + impl MyObj { #[field] - async fn value_a(&self) -> i32 { - 1 - } - - #[field] - async fn value_b(&self) -> i32 { - 2 - } - - #[field] - async fn value_c(&self) -> i32 { - 3 + async fn value(&self) -> FieldResult { + Ok(10) } } - struct MyObjTwo; - - #[async_graphql::Object] - impl MyObjTwo { - #[field] - async fn value_a(&self) -> i32 { - 1 - } - } - - #[async_graphql::Interface(field(name = "value_a", type = "i32"))] - struct InterfaceA(MyObjOne, MyObjTwo); - - #[async_graphql::Interface(field(name = "value_b", type = "i32"))] - struct InterfaceB(MyObjOne); + #[async_graphql::Interface(field(name = "value", type = "FieldResult"))] + struct Node(MyObj); struct Query; #[Object] impl Query { #[field] - async fn my_obj(&self) -> Vec { - vec![MyObjOne.into(), MyObjTwo.into()] + async fn node(&self) -> Node { + MyObj.into() } } - let schema = Schema::build(Query, EmptyMutation, EmptySubscription) - .register_type::() // `InterfaceA` is not directly referenced, so manual registration is required. - .finish(); let query = format!( r#"{{ - myObj {{ - ... on InterfaceA {{ - valueA - }} - ... on InterfaceB {{ - valueB - }} - ... on MyObjOne {{ - valueC - }} + node {{ + ... on Node {{ + value + }} }} }}"# ); + let schema = Schema::new(Query, EmptyMutation, EmptySubscription); assert_eq!( schema.execute(&query).await.unwrap().data, serde_json::json!({ - "myObj": [{ - "valueA": 1, - "valueB": 2, - "valueC": 3, - }, { - "valueA": 1 - }] + "node": { + "value": 10, + } }) ); } +