We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cacache
// MPL-2.0 License const crypto = require('crypto'); const meriyah = require('meriyah'); const cacache = require('cacache'); // const serializer = require('serialize-javascript'); const DEFAULT_OPTIONS = { cacheId: '$$rootId', astBody: false, serialize, deserialize, }; function memoizeFs(options) { let opts = { ...DEFAULT_OPTIONS, ...options, }; if ( !opts.cachePath || (opts.cachePath && typeof opts.cachePath !== 'string') ) { throw new TypeError('options.cachePath is expected to be of type string'); } return { fn(funcToMemoize, settings) { opts = { ...opts, ...settings }; return async function memoizedFn(...args) { const cacheData = generateMeta(funcToMemoize, args, opts); const id = cacheData.hashId; const res = opts.force ? false : await get(id, opts); if (opts.force) { await invalidateCache(id, opts); } if (!res) { const fnResult = await funcToMemoize(...args); const metadata = { ...cacheData, result: fnResult }; const dataString = opts.serialize(metadata); await cacache.put(opts.cachePath, id, dataString, { metadata: { contents: dataString, cacheId: opts.cacheId, salt: opts.salt, }, }); return fnResult; } if (opts.maxAge > 0 && Date.now() > res.time + opts.maxAge) { await invalidateCache(id, opts); } const deserializedValue = opts.deserialize(res.metadata.contents); return deserializedValue; }; }, async invalidate(id, settings) { const opt = { ...opts, ...settings }; if (!id) { await invalidateCache(id, opt); return; } const info = await getInfo(id, opt); const items = [].concat(info).filter(Boolean); await Promise.all( items.map(async (item) => { await invalidateCache(item.key, opt, item.integrity); }), ); }, async getInfo(id, settings) { return getInfo(id, { ...opts, ...settings }); }, }; } async function getInfo(id, opts) { const cache = await cacache.ls(opts.cachePath); const cacheList = Object.keys(cache || {}).map((k) => cache[k]); if (!id || (id && typeof id !== 'string')) { return cacheList.length === 1 ? cacheList[0] : cacheList; } const ids = cacheList.filter((x) => x.metadata.cacheId === id); if (ids.length === 1) { return ids[0]; } if (opts.latest) { const desc = ids.sort((a, b) => b.time - a.time); return desc[0]; } return ids; } async function get(id, opts) { const res = await cacache.get.info(opts.cachePath, id); if (res) { const meta = await cacache.get(opts.cachePath, id); return { ...res, metadata: { ...meta.metadata, contents: meta.data.toString() }, }; } return null; } async function invalidateCache(id, opts, integrity) { if (!id) { await cacache.rm.all(opts.cachePath); await cacache.verify(opts.cachePath); return; } await cacache.rm.entry(opts.cachePath, id); const res = integrity ? { integrity } : await cacache.get.info(opts.cachePath, id); if (res) { await cacache.rm.content(opts.cachePath, res.integrity); } await cacache.verify(opts.cachePath); } function generateMeta(fn, args, options) { const opts = { ...DEFAULT_OPTIONS, ...options, }; const salt = opts.salt || ''; let fnStr = ''; let fnAst = null; if (!opts.noBody) { fnStr = String(fn); if (opts.astBody) { fnAst = meriyah.parse(fnStr, { jsx: true, next: true }); fnStr = JSON.stringify(fnAst); } } const argsStr = opts.serialize(args); const hashId = crypto .createHash('sha256') .update(fnStr + argsStr + opts.cacheId + salt) .digest('hex'); return { fn: fnAst || fn, fnStr, args, argsStr, hashId, }; } function serialize(val) { const circRefColl = []; return JSON.stringify(val, (name, value) => { if (typeof value === 'function') { return; // ignore arguments and attributes of type function silently } if (typeof value === 'object' && value !== null) { if (circRefColl.includes(value)) { // circular reference found, discard key return; } // store value in collection circRefColl.push(value); } // eslint-disable-next-line consistent-return return value; }); } function deserialize(str) { return JSON.parse(str).result; } (async function main() { const memoizer = memoizeFs({ cachePath: './some-cache', // serialize: serializer, // deserialize: (str) => eval(`(${str})`), }); let c = 0; const memoizedFn = memoizer.fn( async (a, b) => { c += a + b; setTimeout(() => Promise.resolve(), 1501); return { a, b, c, help() { console.log('with cacheId and salt', a, b, c); return c; }, }; }, { cacheId: 'some-cache-id', salt: 'b', maxAge: 15000 }, ); // await memoizer.invalidate(); // await memoizer.invalidate('$$rootId'); // await memoizer.invalidate('some-cache-id'); // await memoizer.invalidate('some-cache-id', { latest: true }); console.log(await memoizedFn(1, 2)); console.log(await memoizedFn(1, 2)); // cache hit, or fresh hit when after maxAge console.log(await memoizedFn(1, 2)); // always cache hit console.log(c); })();
The text was updated successfully, but these errors were encountered:
No branches or pull requests
The text was updated successfully, but these errors were encountered: