feat(providence): allow to clear cache of memoized function

This commit is contained in:
Thijs Louisse 2024-05-17 20:32:15 +02:00
parent 1df3854196
commit 994a7b5266
2 changed files with 55 additions and 23 deletions

View file

@ -24,30 +24,33 @@ function createCachableArg(arg) {
/** /**
* @template T * @template T
* @type {<T extends Function>(functionToMemoize:T, opts?:{ storage?:object; }) => T} * @type {<T extends Function>(functionToMemoize:T, opts?:{ cacheStorage?:object; }) => T & {clearCache:() => void}}
*/ */
export function memoize(functionToMemoize, { storage = {} } = {}) { export function memoize(functionToMemoize, { cacheStorage = {} } = {}) {
return /** @type {* & T} */ ( function memoizedFn() {
function memoizedFn() { // eslint-disable-next-line prefer-rest-params
// eslint-disable-next-line prefer-rest-params const args = [...arguments];
const args = [...arguments]; const shouldSerialize = args.some(isObject);
const shouldSerialize = args.some(isObject);
const cachableArgs = shouldSerialize ? args.map(createCachableArg) : args; const cachableArgs = shouldSerialize ? args.map(createCachableArg) : args;
// Allow disabling of cache for testing purposes // Allow disabling of cache for testing purposes
// @ts-expect-error
if (shouldCache && cachableArgs in cacheStorage) {
// @ts-expect-error // @ts-expect-error
if (shouldCache && cachableArgs in storage) { return cacheStorage[cachableArgs];
// @ts-expect-error
return storage[cachableArgs];
}
// @ts-expect-error
const outcome = functionToMemoize.apply(this, args);
// @ts-expect-error
// eslint-disable-next-line no-param-reassign
storage[cachableArgs] = outcome;
return outcome;
} }
); // @ts-expect-error
const outcome = functionToMemoize.apply(this, args);
// @ts-expect-error
// eslint-disable-next-line no-param-reassign
cacheStorage[cachableArgs] = outcome;
return outcome;
}
memoizedFn.clearCache = () => {
// eslint-disable-next-line no-param-reassign
cacheStorage = {};
};
return /** @type {* & T & {clearCache:() => void}} */ (memoizedFn);
} }
/** /**

View file

@ -201,13 +201,13 @@ describe('Memoize', () => {
sumCalled += 1; sumCalled += 1;
return { ...a, ...b }; return { ...a, ...b };
} }
const sumMemoized = memoize(sum, { serializeObjects: true }); const sumMemoized = memoize(sum);
let sum2Called = 0; let sum2Called = 0;
function sum2(/** @type {object} a */ a, /** @type {object} a */ b) { function sum2(/** @type {object} a */ a, /** @type {object} a */ b) {
sum2Called += 1; sum2Called += 1;
return { ...a, ...b }; return { ...a, ...b };
} }
const sum2Memoized = memoize(sum2, { serializeObjects: true }); const sum2Memoized = memoize(sum2);
expect(sumMemoized({ x: 1 }, { y: 2 })).to.deep.equal({ x: 1, y: 2 }); expect(sumMemoized({ x: 1 }, { y: 2 })).to.deep.equal({ x: 1, y: 2 });
expect(sumCalled).to.equal(1); expect(sumCalled).to.equal(1);
@ -233,7 +233,7 @@ describe('Memoize', () => {
sumCalled += 1; sumCalled += 1;
return { ...a, ...b }; return { ...a, ...b };
} }
const sumMemoized = memoize(sum, { serializeObjects: true }); const sumMemoized = memoize(sum);
// Put in cache for args combination // Put in cache for args combination
const result = sumMemoized({ x: 1 }, { y: 2 }); const result = sumMemoized({ x: 1 }, { y: 2 });
@ -313,4 +313,33 @@ describe('Memoize', () => {
expect(sum2Called).to.equal(1); expect(sum2Called).to.equal(1);
}); });
}); });
describe('Cache', () => {
it(`"memoizedFn.clearCache()" clears the cache for a memoized fn"`, async () => {
let sumCalled = 0;
function sum(/** @type {string} a */ a, /** @type {string} a */ b) {
sumCalled += 1;
return a + b;
}
const sumMemoized = memoize(sum);
// Put in cache for args combination
expect(sumMemoized('1', '2')).to.equal('12');
expect(sumCalled).to.equal(1);
// Return from cache
expect(sumMemoized('1', '2')).to.equal('12');
expect(sumCalled).to.equal(1);
sumMemoized.clearCache();
// Now the original function is called again
expect(sumMemoized('1', '2')).to.equal('12');
expect(sumCalled).to.equal(3);
// Return from new cache again
expect(sumMemoized('1', '2')).to.equal('12');
expect(sumCalled).to.equal(3);
});
});
}); });