Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve generate fragment compression #6651

Merged
merged 20 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 91 additions & 4 deletions apollo-federation/src/operation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
//! [`Field`], and the selection type is [`FieldSelection`].

use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::Display;
use std::fmt::Formatter;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;
use std::sync::atomic;
use std::sync::Arc;
Expand Down Expand Up @@ -259,6 +261,12 @@ impl PartialEq for SelectionSet {

impl Eq for SelectionSet {}

impl Hash for SelectionSet {
dariuszkuc marked this conversation as resolved.
Show resolved Hide resolved
fn hash<H: Hasher>(&self, state: &mut H) {
self.selections.hash(state);
dariuszkuc marked this conversation as resolved.
Show resolved Hide resolved
}
}

mod selection_map;

pub(crate) use selection_map::FieldSelectionValue;
Expand All @@ -271,7 +279,7 @@ pub(crate) use selection_map::SelectionValue;

/// An analogue of the apollo-compiler type `Selection` that stores our other selection analogues
/// instead of the apollo-compiler types.
#[derive(Debug, Clone, PartialEq, Eq, derive_more::IsVariant, serde::Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, derive_more::IsVariant, serde::Serialize)]
pub(crate) enum Selection {
Field(Arc<FieldSelection>),
FragmentSpread(Arc<FragmentSpreadSelection>),
Expand Down Expand Up @@ -539,6 +547,76 @@ impl HasSelectionKey for Selection {
}
}

impl Ord for Selection {
fn cmp(&self, other: &Self) -> Ordering {
fn compare_directives(d1: &DirectiveList, d2: &DirectiveList) -> Ordering {
if d1 == d2 {
Ordering::Equal
} else if d1.is_empty() {
Ordering::Less
} else if d2.is_empty() {
Ordering::Greater
} else {
d1.to_string().cmp(&d2.to_string())
dariuszkuc marked this conversation as resolved.
Show resolved Hide resolved
}
}

match (self, other) {
(Selection::Field(f1), Selection::Field(f2)) => {
// cannot have two fields with the same response name so no need to check args or directives
f1.field.response_name().cmp(f2.field.response_name())
}
(Selection::Field(_), _) => Ordering::Less,
(Selection::InlineFragment(_), Selection::Field(_)) => Ordering::Greater,
(Selection::InlineFragment(i1), Selection::InlineFragment(i2)) => {
// compare type conditions and then directives
let first_type_position = &i1.inline_fragment.type_condition_position;
let second_type_position = &i2.inline_fragment.type_condition_position;
match (first_type_position, second_type_position) {
(Some(t1), Some(t2)) => {
let compare_type_conditions = t1.type_name().cmp(t2.type_name());
if compare_type_conditions == Ordering::Equal {
// compare directive lists
compare_directives(
&i1.inline_fragment.directives,
&i2.inline_fragment.directives,
)
} else {
compare_type_conditions
}
}
(Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater,
(None, None) => {
// compare directive lists
compare_directives(
&i1.inline_fragment.directives,
&i2.inline_fragment.directives,
)
}
}
}
(Selection::InlineFragment(_), Selection::FragmentSpread(_)) => Ordering::Less,
(Selection::FragmentSpread(f1), Selection::FragmentSpread(f2)) => {
// compare fragment names
let compare_fragment_names = f1.spread.fragment_name.cmp(&f2.spread.fragment_name);
if compare_fragment_names == Ordering::Equal {
compare_directives(&f1.spread.directives, &f2.spread.directives)
} else {
compare_fragment_names
}
}
(Selection::FragmentSpread(_), _) => Ordering::Greater,
}
}
}

impl PartialOrd for Selection {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

#[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
pub(crate) enum SelectionOrSet {
Selection(Selection),
Expand Down Expand Up @@ -609,7 +687,7 @@ mod field_selection {
/// - For the field definition, stores the schema and the position in that schema instead of just
/// the `FieldDefinition` (which contains no references to the parent type or schema).
/// - Encloses collection types in `Arc`s to facilitate cheaper cloning.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub(crate) struct FieldSelection {
pub(crate) field: Field,
pub(crate) selection_set: Option<SelectionSet>,
Expand Down Expand Up @@ -833,6 +911,9 @@ pub(crate) use field_selection::FieldSelection;
pub(crate) use field_selection::SiblingTypename;

mod fragment_spread_selection {
use std::hash::Hash;
use std::hash::Hasher;

use apollo_compiler::Name;
use serde::Serialize;

Expand All @@ -845,7 +926,7 @@ mod fragment_spread_selection {
use crate::schema::position::CompositeTypeDefinitionPosition;
use crate::schema::ValidFederationSchema;

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub(crate) struct FragmentSpreadSelection {
pub(crate) spread: FragmentSpread,
pub(crate) selection_set: SelectionSet,
Expand Down Expand Up @@ -885,6 +966,12 @@ mod fragment_spread_selection {

impl Eq for FragmentSpread {}

impl Hash for FragmentSpread {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key().hash(state);
}
}

impl HasSelectionKey for FragmentSpread {
fn key(&self) -> SelectionKey<'_> {
if is_deferred_selection(&self.directives) {
Expand Down Expand Up @@ -1000,7 +1087,7 @@ mod inline_fragment_selection {
/// - Stores the parent type explicitly, which means storing the position (in apollo-compiler, this
/// is in the parent selection set).
/// - Encloses collection types in `Arc`s to facilitate cheaper cloning.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub(crate) struct InlineFragmentSelection {
pub(crate) inline_fragment: InlineFragment,
pub(crate) selection_set: SelectionSet,
Expand Down
Loading