Refactor cache module

This commit is contained in:
Schluffe
2026-08-08 14:00:36 +02:00
parent bb071074d2
commit bed4a58cad
7 changed files with 249 additions and 118 deletions
+93
View File
@@ -0,0 +1,93 @@
import { expect, test, vi } from "vitest";
import {
type Cache,
memoize,
withCache,
withCacheAsync,
} from "#/engine/lib/cache.ts";
test("withCache", () => {
const cache: Cache<number> = new Map();
const fn = vi.fn((value: string): number => {
return parseFloat(value);
});
const callback = withCache(fn, cache);
const one = "1";
const res = callback("one", one);
const _ = callback("one", one);
expect(res).toBe(1);
expect(fn).toHaveBeenCalledTimes(1);
expect(callback(2, "2.0")).toBe(2);
expect(fn).toHaveBeenCalledTimes(2);
cache.clear();
expect(callback("one", "1")).toBe(1);
expect(fn).toHaveBeenCalledTimes(3);
});
test("withCacheAsync", async () => {
const cache: Cache<Promise<number>> = new Map();
const fn = vi.fn(async (value: string): Promise<number> => {
return parseFloat(value);
});
const callback = withCacheAsync(fn, cache);
const one = "1";
const res = callback("one", one);
const _ = callback("one", one);
expect(await res).toBe(1);
expect(fn).toHaveBeenCalledTimes(1);
expect(await callback("two", "2")).toBe(2);
expect(fn).toHaveBeenCalledTimes(2);
cache.clear();
expect(await callback("one", "1")).toBe(1);
expect(fn).toHaveBeenCalledTimes(3);
});
test("memoize", () => {
const fn = vi.fn((value: string): number => {
return parseFloat(value);
});
const [callback, cache] = memoize(fn);
const one = "1";
const res = callback(one);
const _ = callback(one);
expect(res).toBe(1);
expect(fn).toHaveBeenCalledTimes(1);
expect(callback("2.0")).toBe(2);
expect(fn).toHaveBeenCalledTimes(2);
cache.clear();
expect(callback("1")).toBe(1);
expect(fn).toHaveBeenCalledTimes(3);
});
test("async memoize", async () => {
const fn = vi.fn(async (value: string): Promise<number> => {
return parseFloat(value);
});
const [callback, cache] = memoize(fn);
const one = "1";
const res = callback(one);
const _ = callback(one);
expect(await res).toBe(1);
expect(fn).toHaveBeenCalledTimes(1);
expect(await callback("2.0")).toBe(2);
expect(fn).toHaveBeenCalledTimes(2);
cache.clear();
expect(await callback("1")).toBe(1);
expect(fn).toHaveBeenCalledTimes(3);
});
+24 -28
View File
@@ -1,52 +1,48 @@
export type Cache<T> = Map<string, T>;
export type AsyncCache<T> = Map<string, Promise<T>>;
export type Cache<T> = Map<unknown, T>;
export function withCache<T, U extends (...args: any[]) => T>(
callback: U,
key: string,
export function withCache<T, U extends (...args: Parameters<U>) => T>(
fn: U,
cache: Cache<T>,
): (...args: Parameters<U>) => T {
return (...args) => {
): (key: unknown, ...args: Parameters<U>) => T {
return (key, ...args) => {
if (cache.has(key)) {
return cache.get(key) as T;
}
const value = callback(...args);
const value = fn(...args);
cache.set(key, value);
return value;
};
}
export function withAsyncCache<T, U extends (...args: any[]) => Promise<T>>(
callback: U,
key: string,
cache: AsyncCache<T>,
): (...args: Parameters<U>) => Promise<T> {
return async (...args) => {
export function withCacheAsync<
T,
U extends (...args: Parameters<U>) => Promise<T>,
>(
fn: U,
cache: Cache<Promise<T>>,
): (key: unknown, ...args: Parameters<U>) => Promise<T> {
return async (key, ...args) => {
if (cache.has(key)) {
return (await cache.get(key)) as T;
}
const value = callback(...args);
const value = fn(...args);
cache.set(key, value);
return await value;
};
}
export function useWithCache<T>(
callback: (...args: any[]) => T,
): [(uri: string) => T, Cache<T>] {
const cache: Cache<T> = new Map();
export function memoize<T, U>(fn: (arg: U) => T): [(arg: U) => T, Cache<T>] {
const cache = new Map<unknown, T>();
const callback = withCache(fn, cache);
return [(uri: string) => withCache(callback, uri, cache)(uri), cache];
}
export function useWithAsyncCache<T>(
callback: (...args: any[]) => Promise<T>,
): [(uri: string) => Promise<T>, AsyncCache<T>] {
const cache: AsyncCache<T> = new Map();
return [(uri: string) => withAsyncCache(callback, uri, cache)(uri), cache];
return [
(arg) => {
return callback(arg, arg);
},
cache,
];
}