Skip to content

Commit

Permalink
fix(package/gqty): Update all relevant temporary caches for batched q…
Browse files Browse the repository at this point in the history
…ueries.
  • Loading branch information
vicary committed May 8, 2024
1 parent 0810986 commit ac34d04
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/green-plants-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gqty': patch
---

Update all relevant temporary caches for batched queries.
8 changes: 7 additions & 1 deletion examples/gnt/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ const withAnalyzer = require('@next/bundle-analyzer')({
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['rickandmortyapi.com'],
remotePatterns: [
{
protocol: 'https',
hostname: 'rickandmortyapi.com',
pathname: '**',
},
],
},
};

Expand Down
49 changes: 34 additions & 15 deletions packages/gqty/src/Client/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MultiDict } from 'multidict';
import { pick, type BaseGeneratedSchema, type FetchOptions } from '.';
import { createSchemaAccessor } from '../Accessor';
import { type Cache } from '../Cache';
Expand Down Expand Up @@ -174,7 +175,7 @@ const pendingQueries = new WeakMap<Set<Set<Selection>>, Promise<unknown>>();
export const createResolvers = <TSchema extends BaseGeneratedSchema>({
aliasLength,
batchWindow,
cache: clientCache,
cache: targetCache,
debugger: debug,
depthLimit,
fetchOptions,
Expand All @@ -186,6 +187,11 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
schema,
parentContext,
}: CreateResolversOptions): Resolvers<TSchema> => {
// A temporary cache is created by the resolver context for no-cache policy.
// When multiple queries are batched, all corresponding temporary caches must
// be updated. Along with the target cache.
const correlatedCaches = new MultiDict<Set<unknown>, Cache>();

const createResolver = ({
cachePolicy = defaultCachePolicy,
extensions,
Expand All @@ -197,7 +203,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
const selections = new Set<Selection>();
const context = createContext({
aliasLength,
cache: clientCache,
cache: targetCache,
depthLimit,
cachePolicy,
scalars,
Expand Down Expand Up @@ -238,15 +244,23 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
}

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

const pendingSelections = addSelections(
clientCache,
targetCache,
selectionsCacheKey,
selections
);

// Link temporary caches together
correlatedCaches.set(pendingSelections, context.cache);

if (!pendingQueries.has(pendingSelections)) {
// [ ] debounceMicrotask

pendingQueries.set(
pendingSelections,
// Batching happens at the end of microtask queue
Expand All @@ -260,7 +274,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({

const uniqueSelections = new Set<Selection>();

getSelectionsSet(clientCache, selectionsCacheKey)?.forEach(
getSelectionsSet(targetCache, selectionsCacheKey)?.forEach(
(selections) => {
selections.forEach((selection) => {
uniqueSelections.add(selection);
Expand All @@ -270,7 +284,7 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({

pendingQueries.delete(pendingSelections);

delSelectionSet(clientCache, selectionsCacheKey);
delSelectionSet(targetCache, selectionsCacheKey);

const results = await fetchSelections(uniqueSelections, {
cache: context.cache,
Expand All @@ -280,13 +294,18 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
operationName,
});

updateCaches(
results,
cachePolicy !== 'no-store' && context.cache !== clientCache
? [context.cache, clientCache]
: [context.cache],
{ skipNotify: !context.notifyCacheUpdate }
);
const targetCaches =
correlatedCaches.get(pendingSelections) ?? new Set();

if (cachePolicy !== 'no-store') {
targetCaches.add(targetCache);
}

updateCaches(results, [...targetCaches], {
skipNotify: !context.notifyCacheUpdate,
});

correlatedCaches.delete(targetCache);

return results;
})
Expand Down Expand Up @@ -375,8 +394,8 @@ export const createResolvers = <TSchema extends BaseGeneratedSchema>({
} else if (data !== undefined) {
updateCaches(
[{ data, error, extensions }],
cachePolicy !== 'no-store' && context.cache !== clientCache
? [context.cache, clientCache]
cachePolicy !== 'no-store' && context.cache !== targetCache
? [context.cache, targetCache]
: [context.cache],
{ skipNotify: !context.notifyCacheUpdate }
);
Expand Down
7 changes: 0 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ac34d04

Please sign in to comment.