diff --git a/.changeset/warm-windows-kiss.md b/.changeset/warm-windows-kiss.md new file mode 100644 index 00000000000..09b14563cf9 --- /dev/null +++ b/.changeset/warm-windows-kiss.md @@ -0,0 +1,10 @@ +--- +'@tanstack/query-core': minor +--- + +Add `enforceQueryGcTime` to `QueryClientConfig` to force `gcTime` for all queries created by a client. + +When provided, this value overrides `gcTime` from: +- `defaultOptions.queries` +- `setQueryDefaults` +- per-query options passed to query methods diff --git a/docs/reference/QueryClient.md b/docs/reference/QueryClient.md index 13bde1ffad0..5bdbb83e8ec 100644 --- a/docs/reference/QueryClient.md +++ b/docs/reference/QueryClient.md @@ -64,6 +64,21 @@ Its available methods are: - Optional - Define defaults for all queries and mutations using this queryClient. - You can also define defaults to be used for [hydration](../framework/react/reference/hydration.md) +- `enforceQueryGcTime?: number` + - Optional + - Forces `gcTime` for every query created by this client, including calls that provide `gcTime` per-query or via `setQueryDefaults`. + - Useful when you need a strict retention policy, for example to keep all query data in cache with `Infinity`. + +```tsx +const queryClient = new QueryClient({ + enforceQueryGcTime: Infinity, + defaultOptions: { + queries: { + gcTime: 60 * 1000, // ignored because enforceQueryGcTime takes precedence + }, + }, +}) +``` ## `queryClient.fetchQuery` diff --git a/packages/query-core/src/__tests__/queryClient.test.tsx b/packages/query-core/src/__tests__/queryClient.test.tsx index 4871d823c1f..a10dcd922a7 100644 --- a/packages/query-core/src/__tests__/queryClient.test.tsx +++ b/packages/query-core/src/__tests__/queryClient.test.tsx @@ -145,6 +145,47 @@ describe('queryClient', () => { }) describe('defaultQueryOptions', () => { + test('should enforce gcTime from QueryClient config', () => { + const key = queryKey() + const testClient = new QueryClient({ + enforceQueryGcTime: Infinity, + }) + + expect( + testClient.defaultQueryOptions({ queryKey: key, gcTime: 10 }).gcTime, + ).toBe(Infinity) + }) + + test('should enforce gcTime over matching query defaults', () => { + const key = queryKey() + const testClient = new QueryClient({ + enforceQueryGcTime: Infinity, + }) + + testClient.setQueryDefaults(key, { gcTime: 10 }) + + expect(testClient.defaultQueryOptions({ queryKey: key }).gcTime).toBe( + Infinity, + ) + }) + + test('should enforce gcTime when query is added to cache', async () => { + const key = queryKey() + const testClient = new QueryClient({ + enforceQueryGcTime: Infinity, + }) + + await testClient.prefetchQuery({ + queryKey: key, + queryFn: () => Promise.resolve('data'), + gcTime: 10, + }) + + expect( + testClient.getQueryCache().find({ queryKey: key })?.options.gcTime, + ).toBe(Infinity) + }) + test('should default networkMode when persister is present', () => { expect( new QueryClient({ diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index 80cc36668aa..027d0f8327f 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -62,6 +62,7 @@ export class QueryClient { #queryCache: QueryCache #mutationCache: MutationCache #defaultOptions: DefaultOptions + #enforceQueryGcTime: number | undefined #queryDefaults: Map #mutationDefaults: Map #mountCount: number @@ -72,6 +73,7 @@ export class QueryClient { this.#queryCache = config.queryCache || new QueryCache() this.#mutationCache = config.mutationCache || new MutationCache() this.#defaultOptions = config.defaultOptions || {} + this.#enforceQueryGcTime = config.enforceQueryGcTime this.#queryDefaults = new Map() this.#mutationDefaults = new Map() this.#mountCount = 0 @@ -593,6 +595,10 @@ export class QueryClient { _defaulted: true, } + if (this.#enforceQueryGcTime !== undefined) { + defaultedOptions.gcTime = this.#enforceQueryGcTime + } + if (!defaultedOptions.queryHash) { defaultedOptions.queryHash = hashQueryKeyByOptions( defaultedOptions.queryKey, diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index 4f3f4caed20..22755e0315a 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -1356,6 +1356,11 @@ export interface QueryClientConfig { queryCache?: QueryCache mutationCache?: MutationCache defaultOptions?: DefaultOptions + /** + * Force all queries created by this client to use the same gcTime. + * This overrides gcTime set globally, per key or per query call. + */ + enforceQueryGcTime?: number } export interface DefaultOptions {