adonis5-cache
Version:
Cache provider for AdonisJS 5
152 lines (151 loc) • 6.13 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const DefaultCacheContext_1 = __importDefault(require("./CacheContexts/DefaultCacheContext"));
const CacheEventEmitter_1 = __importDefault(require("./CacheEventEmitter"));
const ramda_1 = require("ramda");
const TaggableCacheManager_1 = __importDefault(require("./TaggableCacheManager"));
const TypeGuards_1 = require("./TypeGuards");
const ms_1 = __importDefault(require("ms"));
class CacheManager {
constructor({ config, eventEmitter }) {
this.cacheStorages = {};
this.cacheContexts = {};
this.tempContextName = null;
this.tempStorageName = null;
this.cacheTags = [];
this.cacheConfig = config;
this.eventEmitter = new CacheEventEmitter_1.default(this.cacheConfig.enabledEvents, eventEmitter);
this.currentCacheStorageName = this.cacheConfig.currentCacheStorage;
this.initCacheContexts();
}
get recordTTL() {
return this.cacheConfig.recordTTL || CacheManager.DEFAULT_RECORD_TTL;
}
get recordKeyPrefix() {
return this.cacheConfig.cacheKeyPrefix;
}
get context() {
return this.tempContextName
? this.cacheContexts[this.tempContextName]
: this.cacheContexts[this.currentCacheContextName];
}
get storage() {
return this.tempStorageName !== null
? this.cacheStorages[this.tempStorageName]
: this.cacheStorages[this.currentCacheStorageName];
}
registerStorage(storageName, storage) {
this.cacheStorages[storageName] = storage;
return this;
}
registerContext(contextName, context) {
this.cacheContexts[contextName] = context;
return this;
}
viaContext(contextName) {
if (!this.cacheContexts.hasOwnProperty(contextName)) {
throw new Error('Unregistered context for Adonis-Cache');
}
this.tempContextName = contextName;
return this;
}
viaStorage(storageName) {
if (!this.cacheStorages.hasOwnProperty(storageName)) {
throw new Error('Unregistered storage for Adonis-Cache');
}
this.tempStorageName = storageName;
return this;
}
tags(...tags) {
return new TaggableCacheManager_1.default(this, tags);
}
enableStorage(storageName) {
if (!this.cacheStorages.hasOwnProperty(storageName)) {
throw new Error('Unregistered storage for Adonis-Cache');
}
this.currentCacheStorageName = storageName;
return this;
}
enableContext(contextName) {
if (!this.cacheContexts.hasOwnProperty(contextName)) {
throw new Error('Unregistered context for Adonis-Cache');
}
this.currentCacheContextName = contextName;
return this;
}
async get(key, fallback, ttl) {
const cacheValue = await this.storage.get(this.context, this.buildRecordKey(key));
this.emitEventsOnReadOperations({ [key]: cacheValue });
this.restoreState();
return ramda_1.isNil(cacheValue) && fallback
? await this.resolveFallback(key, fallback, this.resolveCacheTTL(ttl))
: cacheValue;
}
async getMany(keys) {
const cachedValues = await this.storage.getMany(this.context, keys.map((key) => this.buildRecordKey(key)));
this.emitEventsOnReadOperations(ramda_1.zipObj(keys, cachedValues));
this.restoreState();
return cachedValues;
}
async put(key, value, ttl) {
const operationResult = await this.storage.put(this.context, this.buildRecordKey(key), value, this.resolveCacheTTL(ttl));
this.eventEmitter.emitEvent('cache-record:written', { [key]: value });
this.restoreState();
return operationResult;
}
async putMany(cacheDictionary, ttl) {
const operationResult = await this.storage.putMany(this.context, Object.entries(cacheDictionary).reduce((acc, [key, value]) => {
return { ...acc, [this.buildRecordKey(key)]: value };
}, {}), this.resolveCacheTTL(ttl));
this.eventEmitter.emitEvent('cache-record:written', cacheDictionary);
this.restoreState();
return operationResult;
}
async flush() {
await this.storage.flush();
}
async forget(key) {
const result = await this.storage.forget(this.buildRecordKey(key));
this.eventEmitter.emitEvent('cache-record:forgotten', { [key]: result });
return result;
}
buildRecordKey(userKey) {
return this.recordKeyPrefix + userKey;
}
restoreState() {
this.tempStorageName = null;
this.tempContextName = null;
this.cacheTags = [];
}
emitEventsOnReadOperations(cacheData) {
const missedKeys = [];
const storedData = {};
for (const [key, value] of Object.entries(cacheData)) {
value === null ? missedKeys.push(key) : Object.assign(storedData, { [key]: value });
}
if (missedKeys.length > 0) {
this.eventEmitter.emitEvent('cache-record:missed', { keys: missedKeys });
}
if (Object.keys(storedData).length > 0) {
this.eventEmitter.emitEvent('cache-record:read', storedData);
}
}
initCacheContexts() {
this.currentCacheContextName = 'DEFAULT';
this.cacheContexts = { [this.currentCacheContextName]: DefaultCacheContext_1.default };
}
async resolveFallback(key, fallback, ttl) {
const fallbackValue = TypeGuards_1.isFunction(fallback) ? await fallback() : fallback;
await this.put(key, fallbackValue, this.resolveCacheTTL(ttl));
return fallbackValue;
}
resolveCacheTTL(ttl) {
const ttlInMilliseconds = Number(ms_1.default((ttl || this.recordTTL) + this.cacheConfig.ttlUnits));
return this.storage.resolveTtl(ttlInMilliseconds);
}
}
exports.default = CacheManager;
CacheManager.DEFAULT_RECORD_TTL = 6000;