This is part of the FetchDependencyGraph::optimize() work.
This PR first makes a few tweaks to operation.rs:
The internal modules normalized_*, like normalized_fragment_spread etc, are now private. The types inside them are reexported from operation.rs directly. The motivation is that it was weird to import NormalizedSelection and NormalizedFieldSelection from different places, and the intention of these modules is just to ensure privacy of fields to maintain invariants, it's not about code organization.
On the topic of maintaining invariants, NormalizedFragmentSpread had public fields, which meant any outside user could violate its invariant (key being in sync with data). Now the fields are private.
Small cleanup: NormalizedSelectionKey isn't borrowable to any other type, but we were using a NormalizedSelectionKey: Borrow<Q> bound, this was more complicated than it needs to be
Then it implements the Selection::contains() / SelectionSet::contains() family of functions. in JS land, .contains() returns a ContainResult enum, which is castable to a boolean. That doesn't make sense in Rust, so instead I add a .containment() function, which returns an enum, and a .contains() shorthand which returns a bool. .containment() checks if the left-hand side (self) contains, is a superset of, the right-hand side (other). There is an option to ignore the case where __typename is present in other but not in self: if provided, self will still be considered to contain other even if self does not have a __typename.
It's a bit confusing but the tests should clarify what that does.
This is part of the
FetchDependencyGraph::optimize()
work.This PR first makes a few tweaks to operation.rs:
normalized_*
, likenormalized_fragment_spread
etc, are now private. The types inside them are reexported fromoperation.rs
directly. The motivation is that it was weird to importNormalizedSelection
andNormalizedFieldSelection
from different places, and the intention of these modules is just to ensure privacy of fields to maintain invariants, it's not about code organization.NormalizedFragmentSpread
had public fields, which meant any outside user could violate its invariant (key being in sync with data). Now the fields are private.NormalizedSelectionKey
isn't borrowable to any other type, but we were using aNormalizedSelectionKey: Borrow<Q>
bound, this was more complicated than it needs to beNormalizedSelectionKey
had separate branches for named fragment spreads and inline fragments. In JS named fragments and inline fragments have the same key, so this is a behaviour change, and it breaks.contains()
. In https://github.com/apollographql/federation-next/pull/290/commits/b2f025456c36f5cad4ebd20485694c4996509fd4 I make sure the selection keys are equivalent to the ones in JS.Then it implements the
Selection::contains()
/SelectionSet::contains()
family of functions. in JS land,.contains()
returns aContainResult
enum, which is castable to a boolean. That doesn't make sense in Rust, so instead I add a.containment()
function, which returns an enum, and a.contains()
shorthand which returns a bool..containment()
checks if the left-hand side (self
) contains, is a superset of, the right-hand side (other
). There is an option to ignore the case where__typename
is present inother
but not inself
: if provided,self
will still be considered to containother
even ifself
does not have a__typename
.It's a bit confusing but the tests should clarify what that does.