UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

84 lines (83 loc) 3.69 kB
import { isNeString } from '@valkyriestudios/utils/string'; export const Sym_TriFrostCached = Symbol('trifrost.cache.cached'); export const Sym_TriFrostSkipCache = Symbol('trifrost.cache.skip'); export function cache(key, opts) { return function (method) { /* Prevent re-decoration */ if (Reflect.get(method, Sym_TriFrostCached)) return method; const wrapped = async function (...args) { const ctx = Array.isArray(args) && args.length ? args[0] : undefined; /* Get trifrost cache either from passed ctx, this.cache or this.ctx.cache */ const trifrost_cache = ctx?.cache ?? this?.cache ?? this?.ctx?.cache; /* No viable cache found */ if (typeof trifrost_cache?.get !== 'function' || typeof trifrost_cache?.set !== 'function') return method.call(this, ...args); /* Determine cache key */ const ckey = typeof key === 'function' ? key(...args.slice(0, key.length)) : isNeString(key) ? key : null; if (!ckey) return method.call(this, ...args); /* Retrieve from cache, if exists -> return */ const cached = await trifrost_cache.get(ckey); if (cached !== null && cached !== undefined) return cached; /* Run method */ const result = await method.call(this, ...args); if (Object.prototype.toString.call(result) === '[object Object]' && Reflect.get(result, Sym_TriFrostSkipCache)) return result.value; /* Cache */ await trifrost_cache.set(ckey, result, opts); return result; }; /* Set to prevent re-decoration */ Reflect.set(wrapped, Sym_TriFrostCached, true); return wrapped; }; } /** * Marks a value as "do not cache", will still return the value directly from the method. */ export function cacheSkip(value) { const v = { value }; Reflect.set(v, Sym_TriFrostSkipCache, true); return v; } /** * Returns whether or not a value is a cache skip value */ export function cacheSkipped(v) { return (Object.prototype.toString.call(v) === '[object Object]' && Reflect.get(v, Sym_TriFrostSkipCache) === true); } export function cacheFn(key, opts) { return function (fn) { /* Prevent re-decoration */ if (Reflect.get(fn, Sym_TriFrostCached)) return fn; const wrapped = async function (...args) { const ctx = Array.isArray(args) && args.length ? args[0] : undefined; const trifrost_cache = ctx?.cache ?? this?.cache ?? this?.ctx?.cache; /* No viable cache found */ if (typeof trifrost_cache?.get !== 'function' || typeof trifrost_cache?.set !== 'function') return fn.apply(this, args); /* Determine cache key */ const ckey = typeof key === 'function' ? key(...args.slice(0, key.length)) : isNeString(key) ? key : null; if (!ckey) return fn.apply(this, args); /* Retrieve from cache, if exists -> return */ const cached = await trifrost_cache.get(ckey); if (cached !== null && cached !== undefined) return cached; /* Run method */ const result = await fn.apply(this, args); if (cacheSkipped(result)) return result.value; /* Cache */ await trifrost_cache.set(ckey, result, opts); return result; }; /* Set to prevent re-decoration */ Reflect.set(wrapped, Sym_TriFrostCached, true); return wrapped; }; }