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

Accommodate @client @export variable changes in ObservableQuery #4604

Merged
merged 9 commits into from
Apr 5, 2019

Conversation

hwillson
Copy link
Member

When using client.watchQuery to setup an Observable against a query that's using @client @export directives, cache changes could happen that lead to the value of the @client @export variable changing. When this happens, if the watched query is using a mixture of local and remote data, the watched query itself might become invalid, since the @client @export variable used to fetch the original data has now changed.

To address this, this PR updates the ObservableQuery observers such that they first check to see if @client @export directives are being used, and update any associated variables. ObservableQuery will then perform a refetch using the new variables if needed, otherwise it will let the observers continue with their normal behaviour.

It's important to note that these changes introduce Promises into ObservableQuery subscription handling, which can impact the timing of ObservableQuery subscriber object calls and/or callbacks. I haven't yet determined how much of an impact this could have in practice, but these changes did impact one existing test suite. I've modified the tests to accommodate these changes (as I believe that test did not represent a real usage scenario), but I think we'll need to consider the impact of these changes carefully before merging.

Fixes #4530.

@hwillson hwillson requested a review from benjamn as a code owner March 20, 2019 01:13
Copy link
Member

@benjamn benjamn left a comment

Choose a reason for hiding this comment

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

Let's take this opportunity to consolidate local state logic, rather than just adding another addExportedVariables call.

packages/apollo-client/src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
packages/apollo-client/src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
packages/apollo-client/src/core/ObservableQuery.ts Outdated Show resolved Hide resolved
When using `client.watchQuery` to setup an Observable against a
query that's using `@client @export` directives, cache changes
could happen that lead to the value of the `@client @export` variable
changing. When this happens, if the watched query is using a mixture
of local and remote data, the watched query itself might become
invalid, since the `@client @export` variable used to fetch
the data has now changed. To address this, this commit updates
the `ObservableQuery` observers such that they first check to see
if `@client @export` directives are being used, and update any
associated variables. It will then perform a `refetch` using the
new variables if needed, otherwise it will let the observers
continue with their normal behaviour.
@benjamn benjamn force-pushed the hwillson/export-refetch-updates branch from 7d0cfd0 to a8f944d Compare April 5, 2019 15:17
@benjamn benjamn added this to the Release 2.6.0 milestone Apr 5, 2019
// changed, and the query is calling against both local and remote
// data, a refetch is needed to pull in new data, using the
// updated `@export` variables.
if (queryManager.transform(query).hasClientExports) {
Copy link
Member

Choose a reason for hiding this comment

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

By using cached data from queryManager.transform(query) we can avoid repeatedly calling hasClientExports or queryManager.getLocalState().serverQuery (below).

@@ -713,7 +713,7 @@ export class QueryManager<TStore> {
}>
>();

private transform(document: DocumentNode) {
public transform(document: DocumentNode) {
Copy link
Member

@benjamn benjamn Apr 5, 2019

Choose a reason for hiding this comment

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

I don't love making this public, but at least the result type is read-only.

@benjamn benjamn merged commit ddb8239 into release-2.6.0 Apr 5, 2019
@benjamn benjamn deleted the hwillson/export-refetch-updates branch April 5, 2019 16:06
benjamn added a commit that referenced this pull request Apr 5, 2019
hwillson added a commit that referenced this pull request Feb 14, 2020
PR #4604 fixed an
issue where changes made to `@client @export` based variables didn't
always result in re-running the query that was using the variable.
Unfortunately, these changes are a bit too aggressive. They're
triggering a `refetch` when an `@client @export` based variable
changes (and a few additional conditions are met), and while using
the `ObservableQuery.refetch()` method does fix the original issue,
it leads to a situation where the query being re-run is always fired
over the network, even if the updated query could have been resolved
from the cache. `ObservableQuery.refetch()` forces queries to use a
network based fetch policy, which means if the query was originally
fired with a `cache-first` policy (for example), and has matching
data in the cache after taking into consideration the new variable,
that data won't be used and instead an extra unnecessary network
request will fire.

This commit addresses the issue by leveraging
`ObservableQuery.setVariables()` instead of automatically
refetching. `setVariables` will attempt to resolve the updated
query from the cache first, then only fire it over the network if
required.
hwillson added a commit that referenced this pull request Feb 14, 2020
PR #4604 fixed an
issue where changes made to `@client @export` based variables didn't
always result in re-running the query that was using the variable.
Unfortunately, these changes are a bit too aggressive. They're
triggering a `refetch` when an `@client @export` based variable
changes (and a few additional conditions are met), and while using
the `ObservableQuery.refetch()` method does fix the original issue,
it leads to a situation where the query being re-run is always fired
over the network, even if the updated query could have been resolved
from the cache. `ObservableQuery.refetch()` forces queries to use a
network based fetch policy, which means if the query was originally
fired with a `cache-first` policy (for example), and has matching
data in the cache after taking into consideration the new variable,
that data won't be used and instead an extra unnecessary network
request will fire.

This commit addresses the issue by leveraging
`ObservableQuery.setVariables()` instead of automatically
refetching. `setVariables` will attempt to resolve the updated
query from the cache first, then only fire it over the network if
required.
hwillson added a commit that referenced this pull request Feb 14, 2020
PR #4604 fixed an
issue where changes made to `@client @export` based variables didn't
always result in re-running the query that was using the variable.
Unfortunately, these changes are a bit too aggressive. They're
triggering a `refetch` when an `@client @export` based variable
changes (and a few additional conditions are met), and while using
the `ObservableQuery.refetch()` method does fix the original issue,
it leads to a situation where the query being re-run is always fired
over the network, even if the updated query could have been resolved
from the cache. `ObservableQuery.refetch()` forces queries to use a
network based fetch policy, which means if the query was originally
fired with a `cache-first` policy (for example), and has matching
data in the cache after taking into consideration the new variable,
that data won't be used and instead an extra unnecessary network
request will fire.

This commit addresses the issue by leveraging
`ObservableQuery.setVariables()` instead of automatically
refetching. `setVariables` will attempt to resolve the updated
query from the cache first, then only fire it over the network if
required.
hwillson added a commit that referenced this pull request Feb 14, 2020
PR #4604 fixed an
issue where changes made to `@client @export` based variables didn't
always result in re-running the query that was using the variable.
Unfortunately, these changes are a bit too aggressive. They're
triggering a `refetch` when an `@client @export` based variable
changes (and a few additional conditions are met), and while using
the `ObservableQuery.refetch()` method does fix the original issue,
it leads to a situation where the query being re-run is always fired
over the network, even if the updated query could have been resolved
from the cache. `ObservableQuery.refetch()` forces queries to use a
network based fetch policy, which means if the query was originally
fired with a `cache-first` policy (for example), and has matching
data in the cache after taking into consideration the new variable,
that data won't be used and instead an extra unnecessary network
request will fire.

This commit addresses the issue by leveraging
`ObservableQuery.setVariables()` instead of automatically
refetching. `setVariables` will attempt to resolve the updated
query from the cache first, then only fire it over the network if
required.
hwillson added a commit that referenced this pull request Feb 15, 2020
PR #4604 fixed an
issue where changes made to `@client @export` based variables didn't
always result in re-running the query that was using the variable.
Unfortunately, these changes are a bit too aggressive. They're
triggering a `refetch` when an `@client @export` based variable
changes (and a few additional conditions are met), and while using
the `ObservableQuery.refetch()` method does fix the original issue,
it leads to a situation where the query being re-run is always fired
over the network, even if the updated query could have been resolved
from the cache. `ObservableQuery.refetch()` forces queries to use a
network based fetch policy, which means if the query was originally
fired with a `cache-first` policy (for example), and has matching
data in the cache after taking into consideration the new variable,
that data won't be used and instead an extra unnecessary network
request will fire.

This commit addresses the issue by leveraging
`ObservableQuery.setVariables()` instead of automatically
refetching. `setVariables` will attempt to resolve the updated
query from the cache first, then only fire it over the network if
required.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants