Skip to content

Commit 9a7a8a1

Browse files
committed
fix(package/gqty): Update all relevant temporary caches for batched queries.
1 parent 0810986 commit 9a7a8a1

4 files changed

Lines changed: 40 additions & 19 deletions

File tree

.changeset/green-plants-breathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'gqty': patch
3+
---
4+
5+
Update all relevant temporary caches for batched queries.

examples/gnt/next.config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ const withAnalyzer = require('@next/bundle-analyzer')({
55
/** @type {import('next').NextConfig} */
66
const nextConfig = {
77
images: {
8-
domains: ['rickandmortyapi.com'],
8+
remotePatterns: [
9+
{
10+
protocol: 'https',
11+
hostname: 'rickandmortyapi.com',
12+
pathname: '**',
13+
},
14+
],
915
},
1016
};
1117

packages/gqty/src/Client/resolvers.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { MultiDict } from 'multidict';
12
import { pick, type BaseGeneratedSchema, type FetchOptions } from '.';
23
import { createSchemaAccessor } from '../Accessor';
34
import { type Cache } from '../Cache';
@@ -174,7 +175,7 @@ const pendingQueries = new WeakMap<Set<Set<Selection>>, Promise<unknown>>();
174175
export const createResolvers = <TSchema extends BaseGeneratedSchema>({
175176
aliasLength,
176177
batchWindow,
177-
cache: clientCache,
178+
cache: targetCache,
178179
debugger: debug,
179180
depthLimit,
180181
fetchOptions,
@@ -186,6 +187,11 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
186187
schema,
187188
parentContext,
188189
}: CreateResolversOptions): Resolvers<TSchema> => {
190+
// A temporary cache is created by the resolver context for no-cache policy.
191+
// When multiple queries are batched, all corresponding temporary caches must
192+
// be updated. Along with the target cache.
193+
const correlatedCaches = new MultiDict<Set<unknown>, Cache>();
194+
189195
const createResolver = ({
190196
cachePolicy = defaultCachePolicy,
191197
extensions,
@@ -197,7 +203,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
197203
const selections = new Set<Selection>();
198204
const context = createContext({
199205
aliasLength,
200-
cache: clientCache,
206+
cache: targetCache,
201207
depthLimit,
202208
cachePolicy,
203209
scalars,
@@ -238,15 +244,23 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
238244
}
239245

240246
// Batch selections up at client level, fetch all of them "next tick".
241-
const selectionsCacheKey = operationName ?? '';
247+
// 1. Query with operation names are never batched up with others.
248+
// 2. 'no-store' queries are tracked separately because its data is not
249+
// going into the main cache.
250+
const selectionsCacheKey = `${operationName ?? (cachePolicy === 'no-store' ? 'no-store' : 'default')}`;
242251

243252
const pendingSelections = addSelections(
244-
clientCache,
253+
targetCache,
245254
selectionsCacheKey,
246255
selections
247256
);
248257

258+
// Link temporary caches together
259+
correlatedCaches.set(pendingSelections, context.cache);
260+
249261
if (!pendingQueries.has(pendingSelections)) {
262+
// [ ] debounceMicrotask
263+
250264
pendingQueries.set(
251265
pendingSelections,
252266
// Batching happens at the end of microtask queue
@@ -260,7 +274,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
260274

261275
const uniqueSelections = new Set<Selection>();
262276

263-
getSelectionsSet(clientCache, selectionsCacheKey)?.forEach(
277+
getSelectionsSet(targetCache, selectionsCacheKey)?.forEach(
264278
(selections) => {
265279
selections.forEach((selection) => {
266280
uniqueSelections.add(selection);
@@ -270,7 +284,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
270284

271285
pendingQueries.delete(pendingSelections);
272286

273-
delSelectionSet(clientCache, selectionsCacheKey);
287+
delSelectionSet(targetCache, selectionsCacheKey);
274288

275289
const results = await fetchSelections(uniqueSelections, {
276290
cache: context.cache,
@@ -282,12 +296,15 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
282296

283297
updateCaches(
284298
results,
285-
cachePolicy !== 'no-store' && context.cache !== clientCache
286-
? [context.cache, clientCache]
287-
: [context.cache],
299+
[
300+
...(cachePolicy === 'no-store' ? [] : [targetCache]),
301+
...(correlatedCaches.get(pendingSelections) ?? []),
302+
],
288303
{ skipNotify: !context.notifyCacheUpdate }
289304
);
290305

306+
correlatedCaches.delete(targetCache);
307+
291308
return results;
292309
})
293310
);
@@ -375,8 +392,8 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
375392
} else if (data !== undefined) {
376393
updateCaches(
377394
[{ data, error, extensions }],
378-
cachePolicy !== 'no-store' && context.cache !== clientCache
379-
? [context.cache, clientCache]
395+
cachePolicy !== 'no-store' && context.cache !== targetCache
396+
? [context.cache, targetCache]
380397
: [context.cache],
381398
{ skipNotify: !context.notifyCacheUpdate }
382399
);

pnpm-lock.yaml

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)