diff --git a/apollo-federation/src/operation/mod.rs b/apollo-federation/src/operation/mod.rs index 71b4aece8b..dca1d7522d 100644 --- a/apollo-federation/src/operation/mod.rs +++ b/apollo-federation/src/operation/mod.rs @@ -895,7 +895,19 @@ impl Selection { } fn sub_selection_type_position(&self) -> Option { - Some(self.selection_set()?.type_position.clone()) + match self { + Selection::Field(field_selection) => field_selection + .selection_set + .as_ref() + .map(|s| s.type_position.clone()), + Selection::FragmentSpread(fragment_selection) => { + Some(fragment_selection.spread.type_condition_position.clone()) + } + Selection::InlineFragment(inline_fragment_selection) => inline_fragment_selection + .inline_fragment + .type_condition_position + .clone(), + } } pub(crate) fn conditions(&self) -> Result { diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests.rs b/apollo-federation/tests/query_plan/build_query_plan_tests.rs index a5a8769c2a..4062311f5b 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests.rs @@ -914,3 +914,43 @@ fn test_merging_fetches_do_not_create_cycle_in_fetch_dependency_graph() { "### ); } + +#[test] +fn redundant_typename_for_inline_fragments_without_type_condition() { + let planner = planner!( + Subgraph1: r#" + type Query { + products: [Product] + } + interface Product { + name: String + } + "#, + ); + assert_plan!( + &planner, + r#" + { + products { + ... @skip(if: false) { + name + } + } + } + "#, + @r###" + QueryPlan { + Fetch(service: "Subgraph1") { + { + products { + __typename + ... @skip(if: false) { + name + } + } + } + }, + } + "### + ); +} diff --git a/apollo-federation/tests/query_plan/supergraphs/redundant_typename_for_inline_fragments_without_type_condition.graphql b/apollo-federation/tests/query_plan/supergraphs/redundant_typename_for_inline_fragments_without_type_condition.graphql new file mode 100644 index 0000000000..0b9050d640 --- /dev/null +++ b/apollo-federation/tests/query_plan/supergraphs/redundant_typename_for_inline_fragments_without_type_condition.graphql @@ -0,0 +1,53 @@ +# Composed from subgraphs with hash: d267b3f18f7736e1a3e39a951696c318d1f46a34 +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) +{ + query: Query +} + +directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE + +directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION + +directive @join__graph(name: String!, url: String!) on ENUM_VALUE + +directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE + +directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR + +directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +scalar join__FieldSet + +enum join__Graph { + SUBGRAPH1 @join__graph(name: "Subgraph1", url: "none") +} + +scalar link__Import + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +interface Product + @join__type(graph: SUBGRAPH1) +{ + name: String +} + +type Query + @join__type(graph: SUBGRAPH1) +{ + products: [Product] +}