All files / fuse-ui-shared/decorators cache.ts

97.37% Statements 37/38
75% Branches 9/12
100% Functions 10/10
97.37% Lines 37/38
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79          1x 1x 1x 1x     91x 91x 2x 2x     91x       91x       31x   31x       4x       31x 31x 28x   3x 3x 3x   3x       1x 1x 1x       1x 1x         1x 1x 1x 1x 1x 31x   1x   1x 1x 1x 1x       1x      
/**
 * cache decorator
 *
 * property decorator that will cache the result for specific time
 */
let objectMap: WeakMap<object, number> = new WeakMap();
let nextObjId = 0;
let expireMap: { [key: string]: Date } = {};
let valueMap: { [key: string]: any } = {};
 
function getObjectKey(obj: object): string {
  let key = objectMap.get(obj);
  if (!key) {
    objectMap.set(obj, ++nextObjId);
    key = nextObjId;
  }
 
  return `${key}`;
}
 
function getCacheKey(obj: object, name: string) {
  return `${getObjectKey(obj)}_${name}`;
}
 
function isCacheValid(obj: object, name: string): boolean {
  let expires = expireMap[getCacheKey(obj, name)];
 
  return expires && expires > new Date();
}
 
function nextExpire(delay: number): Date {
  return new Date(new Date().valueOf() + delay);
}
 
function getCachedValue(obj: object, key: string, inner: Function, expiry: number): any {
  const cacheKey = getCacheKey(obj, key);
  if (isCacheValid(obj, key)) {
    return valueMap[getCacheKey(obj, key)];
  }
  let val = inner.apply(obj);
  expireMap[cacheKey] = nextExpire(expiry);
  valueMap[cacheKey] = val;
 
  return val;
}
 
function setCacheValue(obj: object, key: string, val: any, inner: Function, expiry: number) {
  const cacheKey = getCacheKey(obj, key);
  Eif (inner) {
    inner.call(obj, val);
  } else {
    Object.defineProperty(obj, key, Object.assign(Object.getOwnPropertyDescriptor(obj, key), { value: val }));
  }
  expireMap[cacheKey] = nextExpire(expiry);
  valueMap[cacheKey] = val;
}
 
// tslint:disable:no-invalid-this
// tslint:disable:no-function-expression
export function cache(time: number) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    let innerGet = descriptor.get;
    Eif (typeof innerGet === 'function') {
      let outter = function () {
        return getCachedValue(this, propertyKey, innerGet, time);
      };
      descriptor.get = outter;
    }
    Eif (descriptor.set) {
      let innerSet = descriptor.set;
      descriptor.set = function (val) {
        setCacheValue(this, propertyKey, val, innerSet, time);
      };
    }
 
    return descriptor;
  };
}