@trifrost/core
Version:
Blazingly fast, runtime-agnostic server framework for modern edge and node environments
84 lines (83 loc) • 3.69 kB
JavaScript
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;
};
}