UNPKG

@ngx-toolkit/cache

Version:

Angular cache with Universal support

304 lines (293 loc) 10.7 kB
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