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 fragment reuse #2497

Merged
merged 1 commit into from Mar 30, 2023
Merged

Conversation

pcmanus
Copy link
Contributor

@pcmanus pcmanus commented Mar 24, 2023

The code to try to reuse named fragments inside subgraph queries was a bit "crude" and there was plenty of cases where fragments weren't being reused. The main culprit was know and described in this todo, but there is a few other small points addressed by this PR.

@changeset-bot
Copy link

changeset-bot bot commented Mar 24, 2023

🦋 Changeset detected

Latest commit: 1ae55d3

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

@netlify
Copy link

netlify bot commented Mar 24, 2023

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

Visit the deploys page to approve it

Name Link
🔨 Latest commit 1ae55d3

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 24, 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
Copy link
Contributor Author

pcmanus commented Mar 24, 2023

Marking this as draft for now because I need to write much more tests for this. But it passes tests and was shown to make a big difference on some real world example.

@pcmanus pcmanus force-pushed the improve-fragment-reuse branch 2 times, most recently from fd11718 to 2d5de87 Compare March 27, 2023 14:27
@pcmanus pcmanus marked this pull request as ready for review March 27, 2023 14:27
@pcmanus
Copy link
Contributor Author

pcmanus commented Mar 27, 2023

Added tests and made a few improvements. This is now ready for review.

Improves reuse of named fragments in subgraph fetches. When a question has named fragments, the code tries to reuse
those fragment in subgraph fetches is those can apply (so when the fragment is fully queried in a single subgraph fetch).
However, the existing was only able to reuse those fragment in a small subset of cases. This change makes it much more
like that _if_ a fragment can be reused, it will be.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
like that _if_ a fragment can be reused, it will be.
likely that _if_ a fragment can be reused, it will be.

@@ -2475,6 +2652,36 @@ class FragmentSpreadSelection extends FragmentSelection {
assert(false, 'Unsupported, see `Operation.withAllDeferLabelled`');
}

minus(that: Selection): undefined {
assert(
that instanceof FragmentSpreadSelection && this.namedFragment.name === that.namedFragment.name,
Copy link
Contributor

Choose a reason for hiding this comment

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

Noticing that this is a slightly different clause than is used in equals() further down. Is there a reason for that? If not, should this assertion just use equals()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, using equals should be just fine here.

}

contains(that: Selection): boolean {
if ((that instanceof FragmentSpreadSelection)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use equals() here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point.

}

contains(that: Selection): boolean {
return (that instanceof FragmentSelection)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use equals()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That one we want to keep as-is. equals recursively calls equals on the subselection, but here we're recursively calling contains instead.

contains(that: SelectionSet): boolean {
if (this._selections.length < that._selections.length) {
return false;
private triviallyNestedSelectionsFoKey(parentType: CompositeType, key: string): Selection[] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Here and below

Suggested change
private triviallyNestedSelectionsFoKey(parentType: CompositeType, key: string): Selection[] {
private triviallyNestedSelectionsForKey(parentType: CompositeType, key: string): Selection[] {

The existing code was only able to reuse named fragments in a small
subset of cases (essentially when the fragment was matched by a full
sub-selection). This patch makes the code much more able to reuse
fragments by allowing to match sub-selections, handle intersecting
fragments, etc...
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.

None yet

2 participants