-
-
Notifications
You must be signed in to change notification settings - Fork 26
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
feat: Scoped Queries #1544
Merged
Merged
feat: Scoped Queries #1544
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
vicary
force-pushed
the
feat/scoped-query
branch
from
March 4, 2023 17:15
ca44d1a
to
e947918
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 5, 2023 06:43
e947918
to
4dd548e
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 5, 2023 10:55
4dd548e
to
2b3ecbf
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 5, 2023 13:38
2b3ecbf
to
4e25595
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 9, 2023 15:55
9a0334f
to
05541c1
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 9, 2023 17:36
6f5729d
to
8a32686
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 9, 2023 17:41
8a32686
to
fd71bf4
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 10, 2023 02:11
fd71bf4
to
1eb6377
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 10, 2023 02:14
1eb6377
to
c7f69fe
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 10, 2023 02:26
c7f69fe
to
99fa4b9
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 10, 2023 07:28
99fa4b9
to
13dca64
Compare
vicary
force-pushed
the
feat/scoped-query
branch
2 times, most recently
from
January 30, 2024 08:30
c32fcb5
to
ffc4103
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
January 30, 2024 08:32
ffc4103
to
b2c408b
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
February 25, 2024 09:38
fb99004
to
08987d7
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 23, 2024 14:43
3da1630
to
e4d1b63
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 23, 2024 16:37
e4d1b63
to
523cb55
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 27, 2024 10:40
6d362a5
to
6582130
Compare
vicary
force-pushed
the
feat/scoped-query
branch
from
March 27, 2024 11:21
6582130
to
41b44e5
Compare
Merged
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Current Progress
examples/
intoReact
andVite
, add Svelete and Vue later.--pre
stagesschema
if the legacy accessors still works as intendedScreen_Recording_2023-04-06_at_21.40.15.mov
Screen_Recording_2023-04-07_at_20.24.16.mov
Scoped Queries
The core client has recently gone through a major overhaul, the underlying mechanism is largely rewritten.
To ensure a smooth and progressive migration path, exposed functions are rebuilt with new parts with the API unchanged. If you find a behavioural change and you are not yet ready to fully migrate, please open an issue in GitHub.
Sketch - Scoped Query
Why
The main reason for this overhual is to introduce isolated scoped context for queries and caches. It serves as an extension point for many upcoming features, in fact some of them has already landed here!
What
tl;dr: Axing, pruning and reshaping. A lot of them.
This change removed all centralized internal components, namely, the Scheduler, the Interceptor and the EventHandler.
The new core exposes only two functions,
resovle
andsubscribe
. They cover most, if not all, of the previous API usage.resolve
is a promise based API, built with scoped queries such asfetchPolicy
andoperationName
in mind. It covers the features ofresolved
andinlineResolved
. Subscriptions invoked viaresolve
will be unsubscribed on the first received message for a promise-like experience.subscribe
is an async generator, yielding cache changes from subscriptions or other queries. It covers the originaltrack
feature, while sending the initiating request. Whenquery
ormutation
are used here, it will not return upon response. Instead, it keeps listening to cache changes which may be invoked elsewhere.Both
resolve
andsubscribe
does not restrict the usage ofquery
,mutation
orsubscription
. The only difference issubscribe
streams cache changes, andresolve
is a one-off query.Cache Policy
The existing
fetchPolicy
option is an incomplete copy of the Apollo Client's version, with different functions supporting a different subset of the options.GQty needs an option which make sense across all exposed methods, where users only need to learn once.
I introduced a new
cachePolicy
option, heavily inspired by three popular sources, React Query, Apollo Client and WHATWG.Following Pablo's theme of ESM and web standards, I chose WHATWG's version as the main blueprint. Each of the options are explain below.
default
: Similar to Apollo'scache-first
andcache-and-network
combined. It serves the cached contents when it is fresh, and if they are stale within thestaleWhileRevalidate
window, fetches in the background and updates the cache. Or simply fetches on stale cache or cache miss. During SWR, a successful fetch will not notify cache updates. New contents are served on next query.no-store
: Similar to Apollo'snetwork-only
. It always fetch and does not update on response. GQty creates a temporary cache at query-level which immediately expires.no-cache
: Always fetch, updates on response.force-cache
: Serves the cached contents regardless of staleness. It fetches on cache miss or a stale cache, updates cache on response.only-if-cached
: Similar to Apollo'scache-only
. It serves the cached contents regardless of staleness, throws a network error on cache miss.Sketch - Grand Unified Query & Fetch Policy
Query Deduplication
The active state of query fetches and subscription connections are now kept and deduped on a cache level, preventing excessive network requests on the exact same resources.
Subsequent or duplicated request to ongoing queries gives you the same fetch promise.
More on Subscriptions
Previously, our subscription client was a modified version of
mercurius
. Due to implementation details, some of the existing issues are impossible without a hacky workaround.GQty now accepts a subscription client interface shared by
graphql-ws
andgraphql-sse
, you may easily swap between them or implement your own. The generated client now importsgraphql-ws
when subscriptions are enabled during codegen, where it should be installed separately.Most popular GraphQL servers such as Apollo Server, Mercurius already support both protocols out of the box. If you are using these servers, no changes are required.
The Cache
The cache has been refactored for extensibility, new features such as cache expiry and stale-while-relvidate are one of the first candidates who benefited from it.
Sketch - Cache GC
Cache expiry and stale-while-revalidate
If you are a user of React Query, the new cache options,
maxAge
andstaleWhileRevalidate
, works very similar to theircacheTime
andstaleTime
respectively.The new cache handles expiry a bit different then Apollo Client and React Query. Instead of periodic purges, we use
WeakRef
to offload eviction to the native GC process. This works nicely when combined with our newfetchPolicy
option.Cache Manipulation
There is a new low-level API method
$meta()
, which exposes a number of contextual information about the query proxy, one of them being a direct reference to the cache data.This enables further simplification when it comes to cache manipulation. For example, the
setCache()
function can be easily replaced withObject.assign()
even for query with inputs.For field level cache updates, the existing syntax of
query.me.name = 'Jane Doe';
still works.Normalization
Generally normalization works by hoisting objects that can be uniquely identified to a global store, related subscribers will be notified if multiple queries are referencing the same object.
Normalization with cache expiry is tricky to get right. In a highly simplified scenario, you would need to resolve conflicts with objects that is identifyable with the same ID in these 3 situations:
How
Apart from the main goal of scoped queries, as a secondary side effect of this refactoring, internal components are now less tightly coupled.
Picking the components apart opens up many possibilities in the future. It increases extensibility, improves maintenability and testability.
Axed
@gqty/subscriptions
@gqty/utils
Remade
1. Accessor
The first breaking change is the deprecation of
query
,mutation
andsubscription
. They are now replaced by a singleschema
accessor.The main reason behind this change is to avoid the intrinsic freezing of module level exports. Previously the accessors are exported at the top level from the generated client, locking the scoped context, which prevents new cache contents from being read.
With a proxy shim, these accessors can still read the cache, but they no longer trigger fetches in the background. Network requests must now explicitly made via
resolve
,subscribe
or one of the legacy API functions.2. Cache
In the process of trimming down the core, half of the runtime validations against the schema are removed. Validation is now done via type hinting and type checking.
The cache will become more like a reactive object that triggers rendering, and even more so in future iterations.
3. Client
4. Selection