UNPKG

@trifrost/core

Version:

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

117 lines (116 loc) 4.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Sym_TriFrostSkipCache = exports.Sym_TriFrostCached = void 0; exports.cache = cache; exports.cacheSkip = cacheSkip; exports.cacheSkipped = cacheSkipped; exports.cacheFn = cacheFn; const string_1 = require("@valkyriestudios/utils/string"); const Als_1 = require("../../utils/Als"); exports.Sym_TriFrostCached = Symbol('trifrost.cache.cached'); exports.Sym_TriFrostSkipCache = Symbol('trifrost.cache.skip'); function hasCache(val) { return val?.cache && typeof val.cache.get === 'function' && typeof val.cache.set === 'function'; } /** * Resolve a TriFrostCache instance from any combination of: * - ALS-bound context (if available) * - First argument (if it's a TriFrostContext) * - `this.cache` or `this.ctx.cache` (for instance methods) */ function resolveCache(self, args) { // ALS-bound context const ctxAls = (0, Als_1.ctx)(); if (hasCache(ctxAls)) return ctxAls?.cache; // First argument const ctxArg = Array.isArray(args) && args.length ? args[0] : undefined; if (hasCache(ctxArg)) return ctxArg?.cache; // Fallback to self.cache if (hasCache(self)) return self.cache; // Fallback to self.ctx.cache if (hasCache(self?.ctx)) return self.ctx.cache; return null; } function cache(key, opts) { return function (method) { /* Prevent re-decoration */ if (Reflect.get(method, exports.Sym_TriFrostCached)) return method; const wrapped = async function (...args) { /* Get trifrost cache either from passed ctx, this.cache or this.ctx.cache */ const trifrost_cache = resolveCache(this, args); /* No viable cache found */ if (!trifrost_cache) return method.call(this, ...args); /* Determine cache key */ const ckey = typeof key === 'function' ? key(...args.slice(0, key.length)) : (0, string_1.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, exports.Sym_TriFrostSkipCache)) return result.value; /* Cache */ await trifrost_cache.set(ckey, result, opts); return result; }; /* Set to prevent re-decoration */ Reflect.set(wrapped, exports.Sym_TriFrostCached, true); return wrapped; }; } /** * Marks a value as "do not cache", will still return the value directly from the method. */ function cacheSkip(value) { const v = { value }; Reflect.set(v, exports.Sym_TriFrostSkipCache, true); return v; } /** * Returns whether or not a value is a cache skip value */ function cacheSkipped(v) { return (Object.prototype.toString.call(v) === '[object Object]' && Reflect.get(v, exports.Sym_TriFrostSkipCache) === true); } function cacheFn(key, opts) { return function (fn) { /* Prevent re-decoration */ if (Reflect.get(fn, exports.Sym_TriFrostCached)) return fn; const wrapped = async function (...args) { /* Get trifrost cache either from passed ctx, this.cache or this.ctx.cache */ const trifrost_cache = resolveCache(this, args); /* No viable cache found */ if (!trifrost_cache) return fn.apply(this, args); /* Determine cache key */ const ckey = typeof key === 'function' ? key(...args.slice(0, key.length)) : (0, string_1.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, exports.Sym_TriFrostCached, true); return wrapped; }; }