@nhan2804/nestjs-cacheable
Version:
@nestjs/cacheable is a flexible caching library for NestJS that leverages Redis for efficient and scalable storage. With support for function-level caching through easy-to-use decorators, it allows developers to seamlessly enhance performance while mainta
85 lines (84 loc) • 3.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cacheable = Cacheable;
const cacheable_helpers_1 = require("./cacheable.helpers");
const log = (m) => {
if (cacheable_helpers_1.cacheConfigOption.isDev) {
console.log(m);
}
};
function Cacheable(options) {
return (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function (...args) {
const { ttl, refreshThreshold, key, prefix, type, concatArgs = true, } = Object.assign(Object.assign({}, cacheable_helpers_1.cacheConfigOption), options);
const cacheManager = (0, cacheable_helpers_1.getCacheManager)();
const initKey = `${target.constructor.name}-${propertyKey.toString()}-${args
.map((arg) => (typeof arg === "object" ? JSON.stringify(arg) : arg))
.join("-")}`;
let cacheKey = initKey;
log({
ttl,
refreshThreshold,
key,
prefix,
type,
concatArgs,
});
if (typeof key === "string") {
cacheKey = key;
if (concatArgs) {
cacheKey = `${key}-${initKey}`;
}
}
else if (typeof key === "function") {
cacheKey = key(args);
}
if (!cacheKey) {
throw new Error("cacheKey can not be empty!");
}
log("key " + cacheKey);
const currentTime = Date.now();
if (type === "delete") {
log(`Deleting cache for key: ${cacheKey}`);
await cacheManager.del(cacheKey);
if (prefix) {
const allKeys = await cacheManager.store.keys();
const prefixKeys = allKeys.filter((key) => key.startsWith(prefix));
for (const key of prefixKeys) {
await cacheManager.del(key);
log(`Deleted cache for key with prefix: ${key}`);
}
}
const newValue = await originalMethod.apply(this, args);
await cacheManager.set(cacheKey, { value: newValue, timestamp: currentTime }, ttl);
return newValue;
}
if (type === "bust") {
log(`Force refresh cache for key: ${cacheKey}`);
const newValue = await originalMethod.apply(this, args);
await cacheManager.set(cacheKey, { value: newValue, timestamp: currentTime }, ttl);
return newValue;
}
const cachedData = await cacheManager.get(cacheKey);
if (cachedData) {
const { value, timestamp } = cachedData;
const elapsed = (currentTime - timestamp) / 1000;
const throttleTime = ttl * (refreshThreshold || elapsed);
if (elapsed >= throttleTime) {
log(`Auto-refresh cache for key: ${cacheKey}`);
const newValue = await originalMethod.apply(this, args);
await cacheManager.set(cacheKey, { value: newValue, timestamp: currentTime }, ttl);
return newValue;
}
log(`Cache hit for key: ${cacheKey}`);
return value;
}
log(`Cache miss for key: ${cacheKey}`);
const result = await originalMethod.apply(this, args);
await cacheManager.set(cacheKey, { value: result, timestamp: currentTime }, ttl);
return result;
};
return descriptor;
};
}