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

Fix cases where fragment could be reused but weren't #2541

Merged
merged 2 commits into from
May 3, 2023

Conversation

pcmanus
Copy link
Contributor

@pcmanus pcmanus commented Apr 21, 2023

The main case that was handled properly was the case where a fragment that is on an abstract type is applied somewhere where the "current type" is an object type. In that case, some sub-parts (the one that don't match the "curren type") of the fragment are effectively "dead branches", but the code was still trying to matching those in the result, preventing some reuse of the fragment.

Another smaller issue was that we sometimes weren't correctly reusing fragments at the very top of a "selection set". This didn't really matter too much for queries in practice, but this was also impacting some case where fragments where use at the top level of some other fragments, also preventing a few reuse.

Lastly, fixing this highlighted the fact that the we were always using fragments from the original query, so against the API schema, even when building subgraph queries, and this was creating issues (the code was trying to compensate for this is a few places, but this was confusing and was not covering all cases correctly). So the patch clean this up too, and rebased fragments on subgraph before trying to use them for optimizing said subgraph fetches, ensuring that the code don't mix element from different schema.

@pcmanus pcmanus requested a review from a team as a code owner April 21, 2023 18:17
@netlify
Copy link

netlify bot commented Apr 21, 2023

👷 Deploy request for apollo-federation-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 44a33ae

@changeset-bot
Copy link

changeset-bot bot commented Apr 21, 2023

🦋 Changeset detected

Latest commit: 44a33ae

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@apollo/query-planner Patch
@apollo/federation-internals Patch
@apollo/gateway Patch
@apollo/composition Patch
@apollo/query-graphs Patch
@apollo/subgraph Patch
apollo-federation-integration-testsuite Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 21, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@pcmanus pcmanus force-pushed the fragment-reuse-fixes branch 2 times, most recently from 52056e2 to 851f63b Compare April 21, 2023 18:19
Copy link
Member

@trevor-scheer trevor-scheer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good, mostly just seeking clarity and corrections on some of the comments.

@@ -852,6 +859,7 @@ export class NamedFragmentDefinition extends DirectiveTargetElement<NamedFragmen

setSelectionSet(selectionSet: SelectionSet): NamedFragmentDefinition {
assert(!this._selectionSet, 'Attempting to set the selection set of a fragment definition already built')
assert(selectionSet.parentType === this.typeCondition, `${selectionSet.parentType} !== ${this.typeCondition}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to explain what programming error this assertion intends to catch or have a test that exercises it (I assume this isn't targeted at a user error) since tests pass with or without it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to expand a bit in comments and hope it helps (but no, it isn't targeted at a user error).

Comment on lines 909 to 910
* This methods *assumes* that `this.canApplyAtType(type)` is `true` (and may crash if this is not true), and returns
* a version so this fragment selection set "optimized" when the "current type" is `type`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't quite make sense of this comment, can you correct the grammar?

and returns a version so this fragment selection set "optimized" when the "current type" is type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified. Hopefully that's clearer now.

if (schema === this.schema()) {
return true;
/**
* This methods *assumes* that `this.canApplyAtType(type)` is `true` (and may crash if this is not true), and returns
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured this comment meant that callers should assert that this.canApplyType(type) returns true (and handle false appropriately) before calling this function but that isn't the case. Should we be making that assertion here or at the call site, or is it ok to do neither?

Copy link
Contributor Author

@pcmanus pcmanus May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured this comment meant that callers should assert that this.canApplyType(type) returns true (...)

That is indeed what the comment meant.

(...) but that isn't the case

It is actually the case, but it is slightly indirect. I've added some comments to indicate where that property is checked and where is it propagated through callers.

But I'll note that this.canApplyAtType is not necessarily always super cheap, which is why I'd rather not assert it.

@pcmanus pcmanus force-pushed the fragment-reuse-fixes branch 2 times, most recently from a670859 to 52057c9 Compare May 2, 2023 09:33
Sylvain Lebresne added 2 commits May 3, 2023 10:41
The main case that was handled properly was the case where a fragment
that is on an abstract type is applied somewhere where the "current
type" is an object type. In that case, some sub-parts (the one that don't
match the "curren type") of the fragment are effectively "dead branches",
but the code was still trying to matching those in the result,
preventing some reuse of the fragment.

Another smaller issue was that we sometimes weren't correctly reusing
fragments at the very top of a "selection set". This didn't really
matter too much for queries in practice, but this was also impacting
some case where fragments where use at the top level of some other
fragments, also preventing a few reuse.

Lastly, fixing this highlighted the fact that the we were always using
fragments from the original query, so against the API schema, even when
building subgraph queries, and this was creating issues (the code was
trying to compensate for this is a few places, but this was confusing
and was not covering all cases correctly). So the patch clean this
up too, and rebased fragments on subgraph before trying to use them
for optimizing said subgraph fetches, ensuring that the code don't
mix element from different schema.
@pcmanus pcmanus force-pushed the fragment-reuse-fixes branch from 52057c9 to 44a33ae Compare May 3, 2023 08:48
@pcmanus pcmanus requested a review from trevor-scheer May 3, 2023 08:50
@pcmanus pcmanus merged commit f6a8c1c into apollographql:main May 3, 2023
@github-actions github-actions bot mentioned this pull request May 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants