From f5e4090fa285db8dc10e09b450cee5767437d883 Mon Sep 17 00:00:00 2001 From: Odin Thomas Rochmann Date: Tue, 9 Apr 2024 10:11:17 +0200 Subject: [PATCH] feat(query): allow invalidating of all cache (#2053) --- .changeset/twenty-boxes-wait.md | 29 +++++++++++++ packages/utils/query/src/cache/QueryCache.ts | 2 +- packages/utils/query/src/cache/actions.ts | 43 ++++++++++++++++++- .../utils/query/src/cache/create-reducer.ts | 21 +++++++-- 4 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 .changeset/twenty-boxes-wait.md diff --git a/.changeset/twenty-boxes-wait.md b/.changeset/twenty-boxes-wait.md new file mode 100644 index 000000000..219a76b00 --- /dev/null +++ b/.changeset/twenty-boxes-wait.md @@ -0,0 +1,29 @@ +--- +"@equinor/fusion-query": minor +--- + +`QueryCache` now supports invalidation of all entries + +When not providing key for `QueryCache.invalidate`, all records will be set to invalid + +```diff +QueryCache.ts +- public invalidate(key: string) { ++ public invalidate(key?: string) { + this.#state.next(actions.invalidate(key)); +} +``` + +```diff +create-reducer.ts +.addCase(actions.invalidate, (state, action) => { ++ const invalidKey = action.payload ? [action.payload] : Object.keys(state); +- const entry = state[action.payload]; ++ for (const key of invalidKey) { ++ const entry = state[key]; + if (entry) { + delete entry.updated; + } ++ } +}) +``` diff --git a/packages/utils/query/src/cache/QueryCache.ts b/packages/utils/query/src/cache/QueryCache.ts index 1f598aee2..e9f3cac81 100644 --- a/packages/utils/query/src/cache/QueryCache.ts +++ b/packages/utils/query/src/cache/QueryCache.ts @@ -48,7 +48,7 @@ export class QueryCache { this.#state.next(actions.remove(key)); } - public invalidate(key: string) { + public invalidate(key?: string) { this.#state.next(actions.invalidate(key)); } diff --git a/packages/utils/query/src/cache/actions.ts b/packages/utils/query/src/cache/actions.ts index 4dcf89c0b..1a30aef4b 100644 --- a/packages/utils/query/src/cache/actions.ts +++ b/packages/utils/query/src/cache/actions.ts @@ -1,19 +1,58 @@ import { ActionInstanceMap, ActionTypes, createAction } from '@equinor/fusion-observable'; import { CacheSortFn, QueryCacheRecord } from './types'; +/** + * Creates a set of actions for manipulating the cache. + * + * @template TType - The type of the cache value. + * @template TArgs - The type of the cache arguments. + * @returns An object containing the cache actions. + */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export default function createActions() { return { set: createAction( 'cache/set', + /** + * Sets a cache entry. + * + * @param key - The unique key for the cache entry. + * @param entry - The cache entry object containing value, args, and transaction. + * @returns An action with the type 'cache/set' and the payload containing the key and entry. + */ (key: string, entry: { value: TType; args: TArgs; transaction: string }) => { return { payload: { key, entry } }; }, ), - remove: createAction('cache/remove', (key: string) => ({ payload: key })), - invalidate: createAction('cache/invalidate', (key: string) => ({ payload: key })), + remove: createAction( + 'cache/remove', + /** + * Removes a cache entry. + * + * @param key - The unique key for the cache entry to remove. + * @returns An action with the type 'cache/remove' and the payload containing the key. + */ + (key: string) => ({ payload: key }), + ), + + invalidate: createAction( + 'cache/invalidate', + /** + * Invalidates a cache entry or the entire cache if no key is provided. + * + * @param key - The unique key for the cache entry to invalidate. If omitted, all entries are invalidated. + * @returns An action with the type 'cache/invalidate' and the payload containing the key or undefined. + */ + (key?: string) => ({ payload: key }), + ), trim: createAction( 'cache/trim', + /** + * Trims the cache based on a sorting function, a validation function, and a size limit. + * + * @param payload - An object containing optional sort function, validate function, and size limit. + * @returns An action with the type 'cache/trim' and the payload containing the provided arguments. + */ (payload: { sort?: CacheSortFn; validate?: (item: QueryCacheRecord) => boolean; diff --git a/packages/utils/query/src/cache/create-reducer.ts b/packages/utils/query/src/cache/create-reducer.ts index 286b81220..26878a8a8 100644 --- a/packages/utils/query/src/cache/create-reducer.ts +++ b/packages/utils/query/src/cache/create-reducer.ts @@ -6,10 +6,22 @@ import type { CacheSortFn, QueryCacheRecord, QueryCacheStateData } from './types import { ActionBuilder, Actions } from './actions'; +/** + * Default sorting function for caching, which sorts based on the 'updated' timestamp. + * @param a - The first QueryCacheRecord to compare. + * @param b - The second QueryCacheRecord to compare. + * @returns A number indicating the sort order. + */ const sortCache: CacheSortFn = (a: QueryCacheRecord, b: QueryCacheRecord): number => { return (b.updated ?? 0) - (a.updated ?? 0); }; +/** + * Creates a reducer for managing query cache state. + * @param actions - An instance of ActionBuilder containing action creators. + * @param initial - The initial state of the query cache. + * @returns A reducer function for the query cache state. + */ export default function ( actions: ActionBuilder, initial: QueryCacheStateData = {}, @@ -40,9 +52,12 @@ export default function ( delete state[action.payload]; }) .addCase(actions.invalidate, (state, action) => { - const entry = state[action.payload]; - if (entry) { - delete entry.updated; + const invalidKey = action.payload ? [action.payload] : Object.keys(state); + for (const key of invalidKey) { + const entry = state[key]; + if (entry) { + delete entry.updated; + } } }) .addCase(actions.trim, (state, action) => {