diff --git a/apollo-federation/src/operation/optimize.rs b/apollo-federation/src/operation/optimize.rs index 3590c34f1e..de72f6d74c 100644 --- a/apollo-federation/src/operation/optimize.rs +++ b/apollo-federation/src/operation/optimize.rs @@ -1624,6 +1624,8 @@ fn fragment_name(mut index: usize) -> Name { #[derive(Debug, Default)] struct FragmentGenerator { fragments: NamedFragments, + // XXX(@goto-bus-stop): This is temporary to support mismatch testing with JS! + names: HashMap<(String, usize), usize>, } impl FragmentGenerator { @@ -1631,6 +1633,33 @@ impl FragmentGenerator { fragment_name(self.fragments.len()) } + // XXX(@goto-bus-stop): This is temporary to support mismatch testing with JS! + // In the future, we will just use `.next_name()`. + fn generate_name(&mut self, frag: &InlineFragmentSelection) -> Name { + use std::fmt::Write as _; + + let type_condition = frag + .inline_fragment + .type_condition_position + .as_ref() + .map_or_else( + || "undefined".to_string(), + |condition| condition.to_string(), + ); + let selections = frag.selection_set.selections.len(); + let mut name = format!("_generated_on{type_condition}_{selections}"); + + let key = (type_condition, selections); + let index = self + .names + .entry(key) + .and_modify(|index| *index += 1) + .or_default(); + _ = write!(&mut name, "_{index}"); + + Name::new_unchecked(&name) + } + /// Is a selection set worth using for a newly generated named fragment? fn is_worth_using(selection_set: &SelectionSet) -> bool { let mut iter = selection_set.iter(); @@ -1697,6 +1726,17 @@ impl FragmentGenerator { continue; }; + // XXX(@goto-bus-stop): This is temporary to support mismatch testing with JS! + // JS does not special-case @skip and @include. It never extracts a fragment if + // there's any directives on it. This code duplicates the body from the + // previous condition so it's very easy to remove when we're ready :) + if !skip_include.is_empty() { + new_selection_set.add_local_selection(&Selection::InlineFragment( + Arc::clone(candidate.get()), + ))?; + continue; + } + let existing = self.fragments.iter().find(|existing| { existing.type_condition_position == candidate.get().inline_fragment.casted_type() @@ -1706,7 +1746,9 @@ impl FragmentGenerator { let existing = if let Some(existing) = existing { existing } else { - let name = self.next_name(); + // XXX(@goto-bus-stop): This is temporary to support mismatch testing with JS! + // This should be reverted to `self.next_name();` when we're ready. + let name = self.generate_name(candidate.get()); self.fragments.insert(Fragment { schema: selection_set.schema.clone(), name: name.clone(), diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs index 42e13f473d..69d4d4e5b3 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs @@ -53,14 +53,14 @@ fn it_respects_generate_query_fragments_option() { { t { __typename - ...a + ..._generated_onA_2_0 ... on B { z } } } - fragment a on A { + fragment _generated_onA_2_0 on A { x y } @@ -105,21 +105,21 @@ fn it_handles_nested_fragment_generation() { { t { __typename - ...b + ..._generated_onA_3_0 } } - fragment a on A { + fragment _generated_onA_2_0 on A { x y } - fragment b on A { + fragment _generated_onA_3_0 on A { x y t { __typename - ...a + ..._generated_onA_2_0 ... on B { z } @@ -159,11 +159,11 @@ fn it_handles_fragments_with_one_non_leaf_field() { { t { __typename - ...a + ..._generated_onA_1_0 } } - fragment a on A { + fragment _generated_onA_1_0 on A { t { __typename ... on B { @@ -219,22 +219,23 @@ fn it_migrates_skip_include() { { t { __typename - ...b + ..._generated_onA_3_0 } } - fragment a on A { - x - y - } - - fragment b on A { + fragment _generated_onA_3_0 on A { x y t { __typename - ...a @include(if: $var) - ...a @skip(if: $var) + ... on A @include(if: $var) { + x + y + } + ... on A @skip(if: $var) { + x + y + } ... on A @custom { x y @@ -276,15 +277,15 @@ fn it_identifies_and_reuses_equivalent_fragments_that_arent_identical() { { t { __typename - ...a + ..._generated_onA_2_0 } t2 { __typename - ...a + ..._generated_onA_2_0 } } - fragment a on A { + fragment _generated_onA_2_0 on A { x y } @@ -324,20 +325,20 @@ fn fragments_that_share_a_hash_but_are_not_identical_generate_their_own_fragment { t { __typename - ...a + ..._generated_onA_2_0 } t2 { __typename - ...b + ..._generated_onA_2_1 } } - fragment a on A { + fragment _generated_onA_2_0 on A { x y } - fragment b on A { + fragment _generated_onA_2_1 on A { y z }