This commit is contained in:
parent
88a7571b30
commit
7597523720
6 changed files with 215 additions and 8 deletions
195
integration_tests/juniper_tests/src/issue_798.rs
Normal file
195
integration_tests/juniper_tests/src/issue_798.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
use juniper::{
|
||||||
|
graphql_interface, graphql_object, graphql_value, EmptyMutation, EmptySubscription,
|
||||||
|
GraphQLObject, GraphQLUnion, RootNode, Variables,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[graphql_interface(for = [Human, Droid])]
|
||||||
|
trait Character {
|
||||||
|
fn id(&self) -> &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(GraphQLObject)]
|
||||||
|
#[graphql(impl = CharacterValue)]
|
||||||
|
struct Human {
|
||||||
|
id: String,
|
||||||
|
home_planet: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_interface]
|
||||||
|
impl Character for Human {
|
||||||
|
fn id(&self) -> &str {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(GraphQLObject)]
|
||||||
|
#[graphql(impl = CharacterValue)]
|
||||||
|
struct Droid {
|
||||||
|
id: String,
|
||||||
|
primary_function: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_interface]
|
||||||
|
impl Character for Droid {
|
||||||
|
fn id(&self) -> &str {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(GraphQLUnion)]
|
||||||
|
enum FieldResult {
|
||||||
|
Human(Human),
|
||||||
|
Droid(Droid),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Query {
|
||||||
|
Human,
|
||||||
|
Droid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Query {
|
||||||
|
fn field(&self) -> FieldResult {
|
||||||
|
match self {
|
||||||
|
Self::Human => FieldResult::Human(Human {
|
||||||
|
id: "human-32".to_owned(),
|
||||||
|
home_planet: "earth".to_owned(),
|
||||||
|
}),
|
||||||
|
Self::Droid => FieldResult::Droid(Droid {
|
||||||
|
id: "droid-99".to_owned(),
|
||||||
|
primary_function: "run".to_owned(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Schema = RootNode<'static, Query, EmptyMutation<()>, EmptySubscription<()>>;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_interface_inline_fragment_on_union() {
|
||||||
|
let query = r#"
|
||||||
|
query Query {
|
||||||
|
field {
|
||||||
|
__typename
|
||||||
|
... on Character {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
... on Human {
|
||||||
|
homePlanet
|
||||||
|
}
|
||||||
|
... on Droid {
|
||||||
|
primaryFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let (res, errors) = juniper::execute(
|
||||||
|
query,
|
||||||
|
None,
|
||||||
|
&Schema::new(Query::Human, EmptyMutation::new(), EmptySubscription::new()),
|
||||||
|
&Variables::new(),
|
||||||
|
&(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(errors.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
graphql_value!({
|
||||||
|
"field": {
|
||||||
|
"__typename": "Human",
|
||||||
|
"id": "human-32",
|
||||||
|
"homePlanet": "earth",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (res, errors) = juniper::execute_sync(
|
||||||
|
query,
|
||||||
|
None,
|
||||||
|
&Schema::new(Query::Droid, EmptyMutation::new(), EmptySubscription::new()),
|
||||||
|
&Variables::new(),
|
||||||
|
&(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(errors.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
graphql_value!({
|
||||||
|
"field": {
|
||||||
|
"__typename": "Droid",
|
||||||
|
"id": "droid-99",
|
||||||
|
"primaryFunction": "run",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_interface_fragment_on_union() {
|
||||||
|
let query = r#"
|
||||||
|
query Query {
|
||||||
|
field {
|
||||||
|
__typename
|
||||||
|
... CharacterFragment
|
||||||
|
... on Human {
|
||||||
|
homePlanet
|
||||||
|
}
|
||||||
|
... on Droid {
|
||||||
|
primaryFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment CharacterFragment on Character {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let (res, errors) = juniper::execute(
|
||||||
|
query,
|
||||||
|
None,
|
||||||
|
&Schema::new(Query::Human, EmptyMutation::new(), EmptySubscription::new()),
|
||||||
|
&Variables::new(),
|
||||||
|
&(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(errors.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
graphql_value!({
|
||||||
|
"field": {
|
||||||
|
"__typename": "Human",
|
||||||
|
"id": "human-32",
|
||||||
|
"homePlanet": "earth",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (res, errors) = juniper::execute_sync(
|
||||||
|
query,
|
||||||
|
None,
|
||||||
|
&Schema::new(Query::Droid, EmptyMutation::new(), EmptySubscription::new()),
|
||||||
|
&Variables::new(),
|
||||||
|
&(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(errors.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
graphql_value!({
|
||||||
|
"field": {
|
||||||
|
"__typename": "Droid",
|
||||||
|
"id": "droid-99",
|
||||||
|
"primaryFunction": "run",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
|
@ -19,6 +19,8 @@ mod issue_407;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod issue_500;
|
mod issue_500;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
mod issue_798;
|
||||||
|
#[cfg(test)]
|
||||||
mod issue_914;
|
mod issue_914;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod issue_922;
|
mod issue_922;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# master
|
# master
|
||||||
|
|
||||||
- No changes yet
|
- Allow spreading interface fragments on unions and other interfaces ([#965](https://github.com/graphql-rust/juniper/pull/965), [#798](https://github.com/graphql-rust/juniper/issues/798))
|
||||||
|
|
||||||
# [[0.15.7] 2021-07-08](https://github.com/graphql-rust/juniper/releases/tag/juniper-v0.15.7)
|
# [[0.15.7] 2021-07-08](https://github.com/graphql-rust/juniper/releases/tag/juniper-v0.15.7)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ type Schema =
|
||||||
RootNode<'static, MyQuery, EmptyMutation<MyContext>, MySubscription, DefaultScalarValue>;
|
RootNode<'static, MyQuery, EmptyMutation<MyContext>, MySubscription, DefaultScalarValue>;
|
||||||
|
|
||||||
fn run<O>(f: impl std::future::Future<Output = O>) -> O {
|
fn run<O>(f: impl std::future::Future<Output = O>) -> O {
|
||||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
|
||||||
rt.block_on(f)
|
rt.block_on(f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,7 +307,9 @@ where
|
||||||
|
|
||||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||||
let type_name = instance.type_name(info);
|
let type_name = instance.type_name(info);
|
||||||
if fragment.type_condition.item == concrete_type_name
|
if executor
|
||||||
|
.schema()
|
||||||
|
.is_named_subtype(&concrete_type_name, &fragment.type_condition.item)
|
||||||
|| Some(fragment.type_condition.item) == type_name
|
|| Some(fragment.type_condition.item) == type_name
|
||||||
{
|
{
|
||||||
let sub_result = instance
|
let sub_result = instance
|
||||||
|
@ -351,11 +353,14 @@ where
|
||||||
if let Some(ref type_condition) = fragment.type_condition {
|
if let Some(ref type_condition) = fragment.type_condition {
|
||||||
// Check whether the type matches the type condition.
|
// Check whether the type matches the type condition.
|
||||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||||
if type_condition.item == concrete_type_name {
|
if executor
|
||||||
|
.schema()
|
||||||
|
.is_named_subtype(&concrete_type_name, &type_condition.item)
|
||||||
|
{
|
||||||
let sub_result = instance
|
let sub_result = instance
|
||||||
.resolve_into_type_async(
|
.resolve_into_type_async(
|
||||||
info,
|
info,
|
||||||
type_condition.item,
|
&concrete_type_name,
|
||||||
Some(&fragment.selection_set[..]),
|
Some(&fragment.selection_set[..]),
|
||||||
&sub_exec,
|
&sub_exec,
|
||||||
)
|
)
|
||||||
|
|
|
@ -516,7 +516,9 @@ where
|
||||||
|
|
||||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||||
let type_name = instance.type_name(info);
|
let type_name = instance.type_name(info);
|
||||||
if fragment.type_condition.item == concrete_type_name
|
if executor
|
||||||
|
.schema()
|
||||||
|
.is_named_subtype(&concrete_type_name, &fragment.type_condition.item)
|
||||||
|| Some(fragment.type_condition.item) == type_name
|
|| Some(fragment.type_condition.item) == type_name
|
||||||
{
|
{
|
||||||
let sub_result = instance.resolve_into_type(
|
let sub_result = instance.resolve_into_type(
|
||||||
|
@ -552,10 +554,13 @@ where
|
||||||
if let Some(ref type_condition) = fragment.type_condition {
|
if let Some(ref type_condition) = fragment.type_condition {
|
||||||
// Check whether the type matches the type condition.
|
// Check whether the type matches the type condition.
|
||||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||||
if type_condition.item == concrete_type_name {
|
if executor
|
||||||
|
.schema()
|
||||||
|
.is_named_subtype(&concrete_type_name, &type_condition.item)
|
||||||
|
{
|
||||||
let sub_result = instance.resolve_into_type(
|
let sub_result = instance.resolve_into_type(
|
||||||
info,
|
info,
|
||||||
type_condition.item,
|
&concrete_type_name,
|
||||||
Some(&fragment.selection_set[..]),
|
Some(&fragment.selection_set[..]),
|
||||||
&sub_exec,
|
&sub_exec,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue