@ngx-toolkit/cache
Version:
Angular cache with Universal support
304 lines (293 loc) • 10.7 kB
JavaScript
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { NgModule } from '@angular/core';
import 'reflect-metadata/Reflect';
const CACHE_INSTANCE = {
manager: undefined
};
function initCacheManager(cacheManager) {
CACHE_INSTANCE.manager = cacheManager;
}
function getCacheManager() {
if (!CACHE_INSTANCE.manager) {
throw new Error('No cache found, `initCacheManager` before');
}
return CACHE_INSTANCE.manager;
}
class SimpleCacheManager {
constructor(caches) {
this.setCaches(caches);
}
getCacheNames() {
return Array.from(this.cacheMap.keys());
}
getCache(name) {
return this.cacheMap.get(name) || null;
}
addCache(cache) {
if (!cache) {
throw new Error('Cache is undefined');
}
this.cacheMap.set(cache.name, cache);
}
setCaches(caches) {
this.cacheMap = new Map();
if (caches) {
caches.forEach(cache => this.addCache(cache));
}
}
}
class CacheModule {
/**
* In root module to provide caches
*/
static forRoot(caches) {
initCacheManager(new SimpleCacheManager(caches));
return {
ngModule: CacheModule
};
}
}
CacheModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CacheModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
CacheModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CacheModule, imports: [CommonModule] });
CacheModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CacheModule, imports: [[CommonModule]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: CacheModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule]
}]
}] });
const METADATA_KEY_CACHE_DEFAULTS = '_cache_defaults';
const METADATA_KEY_CACHE_KEYS = '_cache_keys';
const METADATA_KEY_CACHE_VALUE = '_cache_value';
/**
* Allows the configuration of defaults for `CacheResult`, `CachePut`, `CacheRemove`, and `CacheRemoveAll` at the class level.
* Without the method level annotations this annotation has no effect.
*
* @param cacheName
*/
function CacheDefaults(cacheName) {
return (target) => {
Reflect.defineMetadata(METADATA_KEY_CACHE_DEFAULTS, cacheName, target);
};
}
/**
* When a method annotated with `CacheResult` is invoked a cache key will be generated
* and *Cache.get(key)* is called before the annotated method actually executes.
* If a value is found in the cache it is returned and the annotated method is never actually executed.
* If no value is found the annotated method is invoked and the returned value is stored in the cache with the generated key.
*
* @param params (Optional) {cacheName?: string}
*/
function CacheResult(params) {
params = getDefaultParams(params);
return (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const cache = getCache(target, params);
const cacheKey = getCacheKey(target, propertyKey, args);
// Find cache value
let result = cache.get(cacheKey);
// Call function & save function if no cache value
if (result === undefined) {
// Call function & save result
result = originalMethod.apply(this, args);
cache.put(cacheKey, result);
}
return result;
};
return descriptor;
};
}
/**
* Marks a method argument as part of the cache key.
* If no arguments are marked all arguments are used.
* The exception is for a method annotated with `CachePut` where the `CacheValue` parameter is never included in the key.
*/
function CacheKey() {
return (target, propertyKey, parameterIndex) => {
const indices = Reflect.getMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, target, propertyKey) || [];
indices.push(parameterIndex);
Reflect.defineMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, indices, target, propertyKey);
};
}
/**
* When a method annotated with `CachePut` is invoked a cache key will be generated
* and *Cache.put(key, value)* will be invoked on the specified cache storing the value marked with `CacheValue`.
*
* @param params (Optional) {cacheName?: string, afterInvocation: boolean = true}
*/
function CachePut(params) {
params = getDefaultParams(params);
return (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const cache = getCache(target, params);
const indexValue = Reflect.getMetadata(`${METADATA_KEY_CACHE_VALUE}_${propertyKey.toString()}`, target, propertyKey);
const cacheKey = getCacheKey(target, propertyKey, args, indexValue);
if (!params.afterInvocation && indexValue && indexValue >= 0 && indexValue < args.length) {
cache.put(cacheKey, args[indexValue]);
}
const result = originalMethod.apply(this, args);
if (params.afterInvocation && indexValue && indexValue >= 0 && indexValue < args.length) {
cache.put(cacheKey, args[indexValue]);
}
return result;
};
return descriptor;
};
}
/**
* Marks the parameter to be cached for a method annotated with `CachePut`.
*/
function CacheValue() {
return (target, propertyKey, parameterIndex) => {
Reflect.defineMetadata(`${METADATA_KEY_CACHE_VALUE}_${propertyKey.toString()}`, parameterIndex, target, propertyKey);
};
}
/**
* When a method annotated with `CacheRemove` is invoked a cache key will be generated
* and *Cache.remove(key)* will be invoked on the specified cache.
* The default behavior is to call *Cache.evict(key)* after the annotated method is invoked,
* this behavior can be changed by setting *`afterInvocation`* to false in which case *Cache.evict(key)*
* will be called before the annotated method is invoked.
*
* @param params (Optional) {cacheName?: string, afterInvocation: boolean = true}
*/
function CacheRemove(params) {
params = getDefaultParams(params);
return (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const cache = getCache(target, params);
const cacheKey = getCacheKey(target, propertyKey, args);
if (!params.afterInvocation) {
cache.evict(cacheKey);
}
const result = originalMethod.apply(this, args);
if (params.afterInvocation) {
cache.evict(cacheKey);
}
return result;
};
return descriptor;
};
}
/**
* When a method annotated with `CacheRemoveAll` is invoked all elements in the specified cache will be removed via the *Cache.clear()* method.
* The default behavior is to call *Cache.clear()* after the annotated method is invoked,
* this behavior can be changed by setting *`afterInvocation`* to false in which case *Cache.clear()* will be called before the annotated method is invoked.
*
* @param params (Optional) {cacheName?: string, afterInvocation: boolean = true}
*/
function CacheRemoveAll(params) {
params = getDefaultParams(params);
return (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const cache = getCache(target, params);
if (!params.afterInvocation) {
cache.clear();
}
const result = originalMethod.apply(this, args);
if (params.afterInvocation) {
cache.clear();
}
return result;
};
return descriptor;
};
}
function getDefaultParams(cacheParams) {
return Object.assign({
afterInvocation: true
}, cacheParams || {});
}
function getCache(target, params) {
if (!params.cacheName) {
params.cacheName = Reflect.getMetadata(METADATA_KEY_CACHE_DEFAULTS, target.constructor) || '';
}
const cache = getCacheManager().getCache(params.cacheName);
if (!cache) {
throw new Error(`Cache '${params.cacheName}' not found for ${target.constructor.name}`);
}
return cache;
}
function getCacheKey(target, propertyKey, args, cacheValueIndex = -1) {
if (!args) {
args = [];
}
const indices = Reflect.getMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, target, propertyKey);
if (indices) {
args = args.filter((value, index) => indices.indexOf(index) !== -1 && cacheValueIndex !== index);
}
else if (cacheValueIndex !== -1) {
args = args.filter((value, index) => cacheValueIndex !== index);
}
if (args.length === 0) {
throw new Error(`Couldn't generate key without params for '${propertyKey.toString()}' method of ${target.constructor.name}`);
}
return args.map(a => (JSON.stringify(a) || a.toString())).join('|');
}
class NoOpCache {
constructor(name) {
this.name = name;
}
clear() {
}
evict(key) {
}
get(key) {
return undefined;
}
put(key, value) {
}
}
class StorageCache {
constructor(name, storage) {
this.name = name;
this.storage = storage;
}
clear() {
this.storage.clear();
}
evict(key) {
this.storage.removeItem(key);
}
get(key) {
const value = this.storage.getItem(key);
if (!value) {
return undefined;
}
return JSON.parse(value) || null;
}
put(key, value) {
this.storage.setItem(key, JSON.stringify(value));
}
}
class MemoryCache {
constructor(name) {
this.cache = new Map();
this.name = name;
}
clear() {
this.cache.clear();
}
evict(key) {
this.cache.delete(key);
}
get(key) {
return this.cache.get(key);
}
put(key, value) {
this.cache.set(key, value);
}
}
/*
* Public API Surface of cache
*/
/**
* Generated bundle index. Do not edit.
*/
export { CacheDefaults, CacheKey, CacheModule, CachePut, CacheRemove, CacheRemoveAll, CacheResult, CacheValue, MemoryCache, NoOpCache, SimpleCacheManager, StorageCache, getCacheManager, initCacheManager };
//# sourceMappingURL=ngx-toolkit-cache.mjs.map