with-simple-caching
Version:
A wrapper that makes it simple to add caching to any function
62 lines • 3.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.withSimpleCaching = void 0;
const type_fns_1 = require("type-fns");
const getCacheFromCacheOption_1 = require("../options/getCacheFromCacheOption");
const defaults_1 = require("../serde/defaults");
/**
* a wrapper which uses a synchronous cache to cache the result of the wrapped logic
*
* for example:
* ```ts
* const getApiResult = withSimpleCaching(({ name, number }) => axios.get(URL, { name, number }));
* const result1 = getApiResult({ name: 'casey', number: 821 }); // calls the api, puts promise of results into cache, returns that promise
* const result2 = getApiResult({ name: 'casey', number: 821 }); // returns the same promise from above, because it was found in cache - since same input as request above was used
* expect(result1).toBe(result2); // same exact object - the promise
* expect(await result1).toBe(await result2); // same exact object - the result of the promise
* ```
*/
const withSimpleCaching = (logic, { cache: cacheOption, serialize: { key: serializeKey = defaults_1.defaultKeySerializationMethod, // default serialize key to JSON.stringify
value: serializeValue = defaults_1.defaultValueSerializationMethod, // default serialize value to noOp
} = {}, deserialize: { value: deserializeValue = defaults_1.noOp, // default deserialize value to noOp
} = {}, expiration, bypass = {
get: defaults_1.defaultShouldBypassGetMethod,
set: defaults_1.defaultShouldBypassSetMethod,
}, }) => {
return ((...args) => {
var _a, _b;
// define key based on args the function was invoked with
const key = serializeKey({ forInput: args });
// define cache based on options
const cache = (0, getCacheFromCacheOption_1.getCacheFromCacheOption)({ forInput: args, cacheOption });
// see if its already cached
const cachedValue = ((_a = bypass.get) === null || _a === void 0 ? void 0 : _a.call(bypass, args))
? undefined
: cache.get(key);
if ((0, type_fns_1.isNotUndefined)(cachedValue))
return deserializeValue(cachedValue); // if already cached, return it immediately
// if its not, grab the output from the logic
const output = logic(...args);
// if was asked to bypass cache.set, we can return the output now
if ((_b = bypass.set) === null || _b === void 0 ? void 0 : _b.call(bypass, args))
return output;
// set the output to the cache
const serializedOutput = serializeValue(output);
cache.set(key, serializedOutput, { expiration });
// if the output was undefined, we can just return here - no deserialization needed
if (output === undefined)
return output;
// and now re-get from the cache, to ensure that output on first response === output on second response
const cachedValueNow = cache.get(key);
if ((0, type_fns_1.isNotUndefined)(cachedValueNow))
return deserializeValue(cachedValueNow);
// otherwise, somehow, get-after-set returned undefined. warn about this and return output
// eslint-disable-next-line no-console
console.warn(
// warn about this because it should never occur
'withSimpleCaching encountered a situation which should not occur: cache.get returned undefined immediately after having been set. returning the output directly to prevent irrecoverable failure.', { key });
return output;
});
};
exports.withSimpleCaching = withSimpleCaching;
//# sourceMappingURL=withSimpleCaching.js.map