All files / src CacheFactory.ts

93.18% Statements 41/44
83.33% Branches 15/18
100% Functions 2/2
93.18% Lines 41/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 1261x   1x           1x 1x 1x 1x 1x 1x 1x 1x     1x                               1x       1x           1x           1x       8x 2x     6x         1x         5x 1x     4x 2x                   1x       3x 1x   2x 2x 1x 1x 1x       2x 2x       2x 2x       2x 2x       2x 2x 2x 2x                  
import path from 'path';
import { IAgingCache } from './cache/IAgingCache';
import {
  getDefaultAgingCacheOptions,
  AgingCacheWriteMode,
  IAgingCacheOptions,
  AgingCacheReplacementPolicy,
} from './cache/IAgingCacheOptions';
import { RefreshAlwaysSetStrategy } from './cache/RefreshAlwaysSetStrategy';
import { OverwriteAlwaysSetStrategy } from './cache/OverwriteAlwaysSetStrategy';
import { OverwriteAgedSetStrategy } from './cache/OverwriteAgedSetStrategy';
import { RefreshAlwaysDeleteStrategy } from './cache/RefreshAlwaysDeleteStrategy';
import { OverwriteAlwaysDeleteStrategy } from './cache/OverwriteAlwaysDeleteStrategy';
import { OverwriteAgedDeleteStrategy } from './cache/OverwriteAgedDeleteStrategy';
import { Logger } from './shared/Logger';
import { AgingCache } from './cache/AgingCache';
import { IStorageHierarchy } from './storage/IStorageHierarchy';
import { IAgedQueue } from './queue/IAgedQueue';
import { FIFOAgedQueue } from './queue/FIFOAgedQueue';
import {
  IAgingCacheSetStrategy,
  IAgingCacheDeleteStrategy,
} from './cache/IAgingCacheWriteStrategy';
 
type IAgedQueueConstructor = new <TKey>(maxEntries?: number, ageLimit?: number) => IAgedQueue<TKey>;
type IAgingCacheSetStrategyConstructor = new <TKey, TValue>(
  hierarchy: IStorageHierarchy<TKey, TValue>,
  evictQueue: IAgedQueue<TKey>
) => IAgingCacheSetStrategy<TKey, TValue>;
type IAgingCacheDeleteStrategyConstructor = new <TKey, TValue>(
  hierarchy: IStorageHierarchy<TKey, TValue>,
  evictQueue: IAgedQueue<TKey>
) => IAgingCacheDeleteStrategy<TKey, TValue>;
 
const agedQueueMap = new Map<AgingCacheReplacementPolicy, IAgedQueueConstructor>([
  [AgingCacheReplacementPolicy.FIFO, FIFOAgedQueue],
]);
 
const setStrategyMap = new Map<AgingCacheWriteMode, IAgingCacheSetStrategyConstructor>([
  [AgingCacheWriteMode.RefreshAlways, RefreshAlwaysSetStrategy],
  [AgingCacheWriteMode.OverwriteAlways, OverwriteAlwaysSetStrategy],
  [AgingCacheWriteMode.OverwriteAged, OverwriteAgedSetStrategy],
]);
 
const deleteStrategyMap = new Map<AgingCacheWriteMode, IAgingCacheDeleteStrategyConstructor>([
  [AgingCacheWriteMode.RefreshAlways, RefreshAlwaysDeleteStrategy],
  [AgingCacheWriteMode.OverwriteAlways, OverwriteAlwaysDeleteStrategy],
  [AgingCacheWriteMode.OverwriteAged, OverwriteAgedDeleteStrategy],
]);
 
export function checkAgingCacheOptionsValid(
  options: IAgingCacheOptions,
  maxLevel: number
): Error | undefined {
  if (options.maxEntries !== undefined && options.maxEntries < 1) {
    return new Error(`maxEntries(${options.maxEntries}): must be greater than 0`);
  }
 
  if (
    options.ageLimit &&
    options.replacementPolicy === AgingCacheReplacementPolicy.FIFO &&
    options.ageLimit * 60 <= options.purgeInterval
  ) {
    return new Error(
      `maxAge(${options.ageLimit} min): must be greater than purgeInterval(${options.purgeInterval} sec)`
    );
  }
 
  if (options.purgeInterval < 10) {
    return new Error(`purgeInterval(${options.purgeInterval}): must be greater than 10 seconds`);
  }
 
  if (options.evictAtLevel && (options.evictAtLevel < 0 || options.evictAtLevel > maxLevel)) {
    return new Error(`evictAtLevel must be a between 0 and ${maxLevel}`);
  }
}
 
/**
 * Create a new instance of IAgingCache. This function is a factory that will construct the
 * corrent implementation based on the provided options.
 * @param hierarchy The storage hierarchy with the level index 0 being the lowest level
 * @param options Options for the behavior of the cache, if undefined use getDefaultAgingCacheOptions
 */
export function createAgingCache<TKey, TValue>(
  hierarchy: IStorageHierarchy<TKey, TValue>,
  options?: IAgingCacheOptions
): IAgingCache<TKey, TValue> {
  if (!options) {
    options = getDefaultAgingCacheOptions();
  } else {
    const validationError = checkAgingCacheOptionsValid(options, hierarchy.totalLevels - 1);
    if (validationError) {
      const logger = Logger.get(path.basename(__filename));
      logger.error(validationError.message);
      throw validationError;
    }
  }
 
  const agedQueueConstructor = agedQueueMap.get(options.replacementPolicy);
  Iif (!agedQueueConstructor) {
    throw new Error(`Unsupported replacementPolicy: ${options.replacementPolicy}`);
  }
 
  const setStrategyConstructor = setStrategyMap.get(options.setMode);
  Iif (!setStrategyConstructor) {
    throw new Error(`Unsupported setMode: ${options.setMode}`);
  }
 
  const deleteStrategyConstructor = deleteStrategyMap.get(options.deleteMode);
  Iif (!deleteStrategyConstructor) {
    throw new Error(`Unsupported deleteMode: ${options.deleteMode}`);
  }
 
  const evictQueue = new agedQueueConstructor<TKey>(options.maxEntries, options.ageLimit);
  const setStrategy = new setStrategyConstructor(hierarchy, evictQueue);
  const deleteStrategy = new deleteStrategyConstructor(hierarchy, evictQueue);
  return new AgingCache<TKey, TValue>(
    hierarchy,
    evictQueue,
    setStrategy,
    deleteStrategy,
    options.evictAtLevel,
    options.purgeInterval
  );
}