From dc99ae70b8ddc5b49c9304b834a4a308520ceda6 Mon Sep 17 00:00:00 2001 From: ArsileLuci <42055415+ArsileLuci@users.noreply.github.com> Date: Fri, 30 Apr 2021 15:13:54 +0300 Subject: [PATCH] Fix fields on interface not being resolved when used with fragments (#923, #922) --- .../juniper_tests/src/issue_922.rs | 128 ++++++++++++++++++ integration_tests/juniper_tests/src/lib.rs | 2 + juniper/CHANGELOG.md | 2 +- juniper/src/types/async_await.rs | 5 +- juniper/src/types/base.rs | 5 +- 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 integration_tests/juniper_tests/src/issue_922.rs diff --git a/integration_tests/juniper_tests/src/issue_922.rs b/integration_tests/juniper_tests/src/issue_922.rs new file mode 100644 index 00000000..35de87fa --- /dev/null +++ b/integration_tests/juniper_tests/src/issue_922.rs @@ -0,0 +1,128 @@ +use juniper::*; + +struct Query; + +#[juniper::graphql_object] +impl Query { + fn characters() -> Vec { + vec![ + Into::into(Human { + id: 0, + name: "human-32".to_owned(), + }), + Into::into(Droid { + id: 1, + name: "R2-D2".to_owned(), + }), + ] + } +} + +#[juniper::graphql_interface(for = [Human, Droid])] +trait Character { + fn id(&self) -> i32; + + fn name(&self) -> String; +} + +#[derive(juniper::GraphQLObject)] +#[graphql(impl = CharacterValue)] +struct Human { + pub id: i32, + pub name: String, +} + +#[juniper::graphql_interface] +impl Character for Human { + fn id(&self) -> i32 { + self.id + } + + fn name(&self) -> String { + self.name.clone() + } +} + +#[derive(juniper::GraphQLObject)] +#[graphql(impl = CharacterValue)] +struct Droid { + pub id: i32, + pub name: String, +} + +#[juniper::graphql_interface] +impl Character for Droid { + fn id(&self) -> i32 { + self.id + } + + fn name(&self) -> String { + self.name.clone() + } +} + +type Schema = juniper::RootNode<'static, Query, EmptyMutation<()>, EmptySubscription<()>>; + +#[tokio::test] +async fn test_fragment_on_interface() { + let query = r#" + query Query { + characters { + ...CharacterFragment + } + } + + fragment CharacterFragment on Character { + __typename + ... on Human { + id + name + } + ... on Droid { + id + name + } + } + "#; + + let (res, errors) = juniper::execute( + query, + None, + &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()), + &Variables::new(), + &(), + ) + .await + .unwrap(); + + assert_eq!(errors.len(), 0); + assert_eq!( + res, + graphql_value!({ + "characters": [ + {"__typename": "Human", "id": 0, "name": "human-32"}, + {"__typename": "Droid", "id": 1, "name": "R2-D2"}, + ], + }), + ); + + let (res, errors) = juniper::execute_sync( + query, + None, + &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()), + &Variables::new(), + &(), + ) + .unwrap(); + + assert_eq!(errors.len(), 0); + assert_eq!( + res, + graphql_value!({ + "characters": [ + {"__typename": "Human", "id": 0, "name": "human-32"}, + {"__typename": "Droid", "id": 1, "name": "R2-D2"}, + ], + }), + ); +} diff --git a/integration_tests/juniper_tests/src/lib.rs b/integration_tests/juniper_tests/src/lib.rs index ce6123d3..a4a9c97f 100644 --- a/integration_tests/juniper_tests/src/lib.rs +++ b/integration_tests/juniper_tests/src/lib.rs @@ -21,4 +21,6 @@ mod issue_500; #[cfg(test)] mod issue_914; #[cfg(test)] +mod issue_922; +#[cfg(test)] mod pre_parse; diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md index 273a0087..f71fce95 100644 --- a/juniper/CHANGELOG.md +++ b/juniper/CHANGELOG.md @@ -1,6 +1,6 @@ # master -- No changes yet +- Fix fields on interfaces not being resolved when used with fragments ([#923](https://github.com/graphql-rust/juniper/pull/923)) # [[0.15.4] 2021-04-03](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.15.4) diff --git a/juniper/src/types/async_await.rs b/juniper/src/types/async_await.rs index e1f6e6e1..4fd16aad 100644 --- a/juniper/src/types/async_await.rs +++ b/juniper/src/types/async_await.rs @@ -306,7 +306,10 @@ where ); let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info); - if fragment.type_condition.item == concrete_type_name { + let type_name = instance.type_name(info); + if fragment.type_condition.item == concrete_type_name + || Some(fragment.type_condition.item) == type_name + { let sub_result = instance .resolve_into_type_async( info, diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs index 61d32ca8..014af5de 100644 --- a/juniper/src/types/base.rs +++ b/juniper/src/types/base.rs @@ -515,7 +515,10 @@ where ); let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info); - if fragment.type_condition.item == concrete_type_name { + let type_name = instance.type_name(info); + if fragment.type_condition.item == concrete_type_name + || Some(fragment.type_condition.item) == type_name + { let sub_result = instance.resolve_into_type( info, fragment.type_condition.item,