Check type before resolving in inline fragments to fix panic when using inline fragments with interfaces (#816, #815)
This commit is contained in:
parent
4ffd276a5b
commit
2c15ea798c
4 changed files with 75 additions and 29 deletions
|
@ -51,6 +51,10 @@ where
|
|||
QueryT::name(info)
|
||||
}
|
||||
|
||||
fn concrete_type_name(&self, context: &Self::Context, info: &Self::TypeInfo) -> String {
|
||||
self.query_type.concrete_type_name(context, info)
|
||||
}
|
||||
|
||||
fn resolve_field(
|
||||
&self,
|
||||
info: &Self::TypeInfo,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
ast::InputValue,
|
||||
executor::Variables,
|
||||
graphql_value,
|
||||
schema::model::RootNode,
|
||||
tests::fixtures::starwars::schema::{Database, Query},
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
|
@ -731,3 +732,36 @@ async fn test_object_typename() {
|
|||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_inline_fragment_friends() {
|
||||
let doc = r#"{
|
||||
human(id: "1002") {
|
||||
friends {
|
||||
name
|
||||
... on Human { homePlanet }
|
||||
... on Droid { primaryFunction }
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let database = Database::new();
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
EmptyMutation::<Database>::new(),
|
||||
EmptySubscription::<Database>::new(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
crate::execute(doc, None, &schema, &Variables::new(), &database).await,
|
||||
Ok((
|
||||
graphql_value!({"human": {
|
||||
"friends": [
|
||||
{"name": "Luke Skywalker", "homePlanet": "Tatooine"},
|
||||
{"name": "Leia Organa", "homePlanet": "Alderaan"},
|
||||
{"name": "R2-D2", "primaryFunction": "Astromech"},
|
||||
],
|
||||
}}),
|
||||
vec![],
|
||||
))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -323,26 +323,30 @@ where
|
|||
);
|
||||
|
||||
if let Some(ref type_condition) = fragment.type_condition {
|
||||
let sub_result = instance
|
||||
.resolve_into_type_async(
|
||||
info,
|
||||
type_condition.item,
|
||||
Some(&fragment.selection_set[..]),
|
||||
&sub_exec,
|
||||
)
|
||||
.await;
|
||||
// Check whether the type matches the type condition.
|
||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||
if type_condition.item == concrete_type_name {
|
||||
let sub_result = instance
|
||||
.resolve_into_type_async(
|
||||
info,
|
||||
type_condition.item,
|
||||
Some(&fragment.selection_set[..]),
|
||||
&sub_exec,
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Ok(Value::Object(obj)) = sub_result {
|
||||
for (k, v) in obj {
|
||||
async_values.push(AsyncValueFuture::InlineFragment1(async move {
|
||||
AsyncValue::Field(AsyncField {
|
||||
name: k,
|
||||
value: Some(v),
|
||||
})
|
||||
}));
|
||||
if let Ok(Value::Object(obj)) = sub_result {
|
||||
for (k, v) in obj {
|
||||
async_values.push(AsyncValueFuture::InlineFragment1(async move {
|
||||
AsyncValue::Field(AsyncField {
|
||||
name: k,
|
||||
value: Some(v),
|
||||
})
|
||||
}));
|
||||
}
|
||||
} else if let Err(e) = sub_result {
|
||||
sub_exec.push_error_at(e, *start_pos);
|
||||
}
|
||||
} else if let Err(e) = sub_result {
|
||||
sub_exec.push_error_at(e, *start_pos);
|
||||
}
|
||||
} else {
|
||||
async_values.push(AsyncValueFuture::InlineFragment2(async move {
|
||||
|
|
|
@ -532,19 +532,23 @@ where
|
|||
);
|
||||
|
||||
if let Some(ref type_condition) = fragment.type_condition {
|
||||
let sub_result = instance.resolve_into_type(
|
||||
info,
|
||||
type_condition.item,
|
||||
Some(&fragment.selection_set[..]),
|
||||
&sub_exec,
|
||||
);
|
||||
// Check whether the type matches the type condition.
|
||||
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
|
||||
if type_condition.item == concrete_type_name {
|
||||
let sub_result = instance.resolve_into_type(
|
||||
info,
|
||||
type_condition.item,
|
||||
Some(&fragment.selection_set[..]),
|
||||
&sub_exec,
|
||||
);
|
||||
|
||||
if let Ok(Value::Object(object)) = sub_result {
|
||||
for (k, v) in object {
|
||||
merge_key_into(result, &k, v);
|
||||
if let Ok(Value::Object(object)) = sub_result {
|
||||
for (k, v) in object {
|
||||
merge_key_into(result, &k, v);
|
||||
}
|
||||
} else if let Err(e) = sub_result {
|
||||
sub_exec.push_error_at(e, *start_pos);
|
||||
}
|
||||
} else if let Err(e) = sub_result {
|
||||
sub_exec.push_error_at(e, *start_pos);
|
||||
}
|
||||
} else if !resolve_selection_set_into(
|
||||
instance,
|
||||
|
|
Loading…
Reference in a new issue