Skip to content

Commit 2c15ea7

Browse files
Check type before resolving in inline fragments to fix panic when using inline fragments with interfaces (#816, #815)
1 parent 4ffd276 commit 2c15ea7

File tree

4 files changed

+77
-31
lines changed

4 files changed

+77
-31
lines changed

juniper/src/schema/schema.rs

+4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ where
5151
QueryT::name(info)
5252
}
5353

54+
fn concrete_type_name(&self, context: &Self::Context, info: &Self::TypeInfo) -> String {
55+
self.query_type.concrete_type_name(context, info)
56+
}
57+
5458
fn resolve_field(
5559
&self,
5660
info: &Self::TypeInfo,

juniper/src/tests/query_tests.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
ast::InputValue,
33
executor::Variables,
4+
graphql_value,
45
schema::model::RootNode,
56
tests::fixtures::starwars::schema::{Database, Query},
67
types::scalars::{EmptyMutation, EmptySubscription},
@@ -731,3 +732,36 @@ async fn test_object_typename() {
731732
))
732733
);
733734
}
735+
736+
#[tokio::test]
737+
async fn interface_inline_fragment_friends() {
738+
let doc = r#"{
739+
human(id: "1002") {
740+
friends {
741+
name
742+
... on Human { homePlanet }
743+
... on Droid { primaryFunction }
744+
}
745+
}
746+
}"#;
747+
let database = Database::new();
748+
let schema = RootNode::new(
749+
Query,
750+
EmptyMutation::<Database>::new(),
751+
EmptySubscription::<Database>::new(),
752+
);
753+
754+
assert_eq!(
755+
crate::execute(doc, None, &schema, &Variables::new(), &database).await,
756+
Ok((
757+
graphql_value!({"human": {
758+
"friends": [
759+
{"name": "Luke Skywalker", "homePlanet": "Tatooine"},
760+
{"name": "Leia Organa", "homePlanet": "Alderaan"},
761+
{"name": "R2-D2", "primaryFunction": "Astromech"},
762+
],
763+
}}),
764+
vec![],
765+
))
766+
);
767+
}

juniper/src/types/async_await.rs

+23-19
Original file line numberDiff line numberDiff line change
@@ -323,26 +323,30 @@ where
323323
);
324324

325325
if let Some(ref type_condition) = fragment.type_condition {
326-
let sub_result = instance
327-
.resolve_into_type_async(
328-
info,
329-
type_condition.item,
330-
Some(&fragment.selection_set[..]),
331-
&sub_exec,
332-
)
333-
.await;
334-
335-
if let Ok(Value::Object(obj)) = sub_result {
336-
for (k, v) in obj {
337-
async_values.push(AsyncValueFuture::InlineFragment1(async move {
338-
AsyncValue::Field(AsyncField {
339-
name: k,
340-
value: Some(v),
341-
})
342-
}));
326+
// Check whether the type matches the type condition.
327+
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
328+
if type_condition.item == concrete_type_name {
329+
let sub_result = instance
330+
.resolve_into_type_async(
331+
info,
332+
type_condition.item,
333+
Some(&fragment.selection_set[..]),
334+
&sub_exec,
335+
)
336+
.await;
337+
338+
if let Ok(Value::Object(obj)) = sub_result {
339+
for (k, v) in obj {
340+
async_values.push(AsyncValueFuture::InlineFragment1(async move {
341+
AsyncValue::Field(AsyncField {
342+
name: k,
343+
value: Some(v),
344+
})
345+
}));
346+
}
347+
} else if let Err(e) = sub_result {
348+
sub_exec.push_error_at(e, *start_pos);
343349
}
344-
} else if let Err(e) = sub_result {
345-
sub_exec.push_error_at(e, *start_pos);
346350
}
347351
} else {
348352
async_values.push(AsyncValueFuture::InlineFragment2(async move {

juniper/src/types/base.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -532,19 +532,23 @@ where
532532
);
533533

534534
if let Some(ref type_condition) = fragment.type_condition {
535-
let sub_result = instance.resolve_into_type(
536-
info,
537-
type_condition.item,
538-
Some(&fragment.selection_set[..]),
539-
&sub_exec,
540-
);
541-
542-
if let Ok(Value::Object(object)) = sub_result {
543-
for (k, v) in object {
544-
merge_key_into(result, &k, v);
535+
// Check whether the type matches the type condition.
536+
let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
537+
if type_condition.item == concrete_type_name {
538+
let sub_result = instance.resolve_into_type(
539+
info,
540+
type_condition.item,
541+
Some(&fragment.selection_set[..]),
542+
&sub_exec,
543+
);
544+
545+
if let Ok(Value::Object(object)) = sub_result {
546+
for (k, v) in object {
547+
merge_key_into(result, &k, v);
548+
}
549+
} else if let Err(e) = sub_result {
550+
sub_exec.push_error_at(e, *start_pos);
545551
}
546-
} else if let Err(e) = sub_result {
547-
sub_exec.push_error_at(e, *start_pos);
548552
}
549553
} else if !resolve_selection_set_into(
550554
instance,

0 commit comments

Comments
 (0)