forked from pinks/eris
1
0
Fork 0
eris/app/kvMemoize.ts

46 lines
1.3 KiB
TypeScript

/**
* Memoizes the function result in KV storage.
*/
export function kvMemoize<A extends Deno.KvKey, R>(
db: Deno.Kv,
key: Deno.KvKey,
fn: (...args: A) => Promise<R>,
options?: {
expireIn?: number | ((result: R, ...args: A) => number);
shouldRecalculate?: (result: R, ...args: A) => boolean;
shouldCache?: (result: R, ...args: A) => boolean;
override?: {
set: (key: Deno.KvKey, args: A, value: R, options: { expireIn?: number }) => Promise<void>;
get: (key: Deno.KvKey, args: A) => Promise<R | undefined>;
};
},
): (...args: A) => Promise<R> {
return async (...args) => {
const cachedResult = options?.override?.get
? await options.override.get(key, args)
: (await db.get<R>([...key, ...args])).value;
if (cachedResult != null) {
if (!options?.shouldRecalculate?.(cachedResult, ...args)) {
return cachedResult;
}
}
const result = await fn(...args);
const expireIn = typeof options?.expireIn === "function"
? options.expireIn(result, ...args)
: options?.expireIn;
if (options?.shouldCache?.(result, ...args) ?? (result != null)) {
if (options?.override?.set) {
await options.override.set(key, args, result, { expireIn });
} else {
await db.set([...key, ...args], result, { expireIn });
}
}
return result;
};
}