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

Avoid full reapplication of cache-and-network and network-only fetch policies after successful fetchMore #9504

Merged
merged 21 commits into from
Mar 29, 2022

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Mar 8, 2022

This PR implements a variation on the idea I sketched in #6916 (comment), without doing too much violence to our existing test suite. I did end up making a number of adjustments to tests that this PR initially caused to fail, but I'm confident they are nonviolent (that is, they test the same things in a more robust/realistic way).

Previous attempts to solve #6916 stalled in part because the number of test failures felt indicative of potential backwards incompatibility. Now that I've worked through all the failing tests in this PR, I believe they are mostly just fragile/flaky/timing-sensitive tests, though of course it would be great to validate that hope with beta testing.

In short, fetchMore should (now) be able to deliver complete cache results to ObservableQuery subscribers without triggering additional network requests when using the cache-and-network or network-only fetch policies, resolving the following related (some long-standing) issues:

@benjamn benjamn added this to the Release 3.6 milestone Mar 8, 2022
@benjamn benjamn self-assigned this Mar 8, 2022
src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
@benjamn benjamn changed the title Avoid full reapplication of network fetch policies after successful fetchMore Avoid full reapplication of cache-and-network and network-only fetch policies after successful fetchMore Mar 9, 2022
src/core/QueryInfo.ts Outdated Show resolved Hide resolved
src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
@benjamn benjamn force-pushed the avoid-full-reobservation-after-fetchMore branch from 5f3ea17 to 0850e3a Compare March 9, 2022 18:56
@benjamn benjamn marked this pull request as ready for review March 9, 2022 21:14
@benjamn benjamn force-pushed the avoid-full-reobservation-after-fetchMore branch from c47e347 to 387fb97 Compare March 10, 2022 19:05
Comment on lines -404 to -419
if (__DEV__ &&
!warnedAboutUpdateQuery) {
invariant.warn(
`The updateQuery callback for fetchMore is deprecated, and will be removed
in the next major version of Apollo Client.

Please convert updateQuery functions to field policies with appropriate
read and merge functions, or use/adapt a helper function (such as
concatPagination, offsetLimitPagination, or relayStylePagination) from
@apollo/client/utilities.

The field policy system handles pagination more effectively than a
hand-written updateQuery function, and you only need to define the policy
once, rather than every time you call fetchMore.`);
warnedAboutUpdateQuery = true;
}
Copy link
Member Author

@benjamn benjamn Mar 10, 2022

Choose a reason for hiding this comment

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

Removing this warning is something a number of developers have requested (for example, this twitter discussion). At this point, I believe the warning has done all the good it can do (nudging people to stop using updateQuery and use field policies instead), so removing the warning will improve the lives of developers who still have a good reason to use updateQuery. Also, updateQuery is now implemented in terms of cache.updateQuery (#8382), which is an API we intend to continue supporting.

@benjamn benjamn force-pushed the avoid-full-reobservation-after-fetchMore branch 2 times, most recently from e8d2536 to 3c3eb1f Compare March 11, 2022 17:24
benjamn added a commit that referenced this pull request Mar 11, 2022
Although these test updates may seem substantial, I believe this
refactoring makes the tests more robust without changing what they test.
To that end, it's important to note these tests are all passing at this
point in the commit history, before any of the more substantive changes
from PR #9504, and continue passing even after those changes are
introduced, with relatively few additional test changes.
@benjamn benjamn force-pushed the avoid-full-reobservation-after-fetchMore branch from 3c3eb1f to bb83bca Compare March 11, 2022 17:47
@benjamn
Copy link
Member Author

benjamn commented Mar 11, 2022

As a demonstration of the safety of the src/__tests__/fetchMore.ts test changes, I rebased commit bb83bca all the way to the beginning of the branch, then force-pushed it by itself, so it's easy to see the modified tests passing in CI before reviewing the rest of the commits.

benjamn added a commit that referenced this pull request Mar 11, 2022
src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
Copy link
Member

@hwillson hwillson left a comment

Choose a reason for hiding this comment

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

Looks great @benjamn - thanks!

Although these test updates may seem substantial, I believe this
refactoring makes the tests more robust without changing what they test.
To that end, it's important to note these tests are all passing at this
point in the commit history, before any of the more substantive changes
from PR #9504, and continue passing even after those changes are
introduced, with relatively few additional test changes.
Now that fetchMore's updateQuery callback is implemented in terms of the
supported/documented cache.updateQuery method, I feel better about
allowing fetchMore to continue to take an updateQuery callback.

Also, everyone with any ability to migrate from updateQuery to
InMemoryCache field policies has presumably already done so, so this
warning is less useful now than it was following the release of AC3.
When `!diff.complete`, `oq.reobserveCacheFirst()` should behave exactly
like `oq.reobserve()`, since the fetch policies `reobserveCacheFirst`
modifies (`network-only` and `cache-and-network`) behave the same as the
`cache-first` policy when cache results are incomplete.
This reverts commits d5463be and
0170f32, with a new test showing why
the backup reobserveCacheFirst call in the finally block is important:
sometimes the cache write doesn't change any data in the cache, so no
broadcast happens, but we still need to deliver the final loading:false
result for the fetchMore request.
@benjamn benjamn force-pushed the avoid-full-reobservation-after-fetchMore branch from 1bf0867 to 5036dc5 Compare March 29, 2022 18:19
@benjamn benjamn merged commit f6fb1ec into release-3.6 Mar 29, 2022
@benjamn benjamn deleted the avoid-full-reobservation-after-fetchMore branch March 29, 2022 19:51
@benjamn
Copy link
Member Author

benjamn commented Mar 29, 2022

These changes have been published to npm as @apollo/client@3.6.0-beta.10.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.