All files / src/cache AgingCacheWriteStrategy.ts

85.18% Statements 23/27
33.33% Branches 3/9
100% Functions 8/8
85.18% Lines 23/27

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 877x   7x           7x 28x             28x 28x     28x 7x 7x 7x       7x       28x         6x       6x 6x 6x       6x       28x       5x 5x               5x                     13x 13x                      
import { Logger } from '../shared/Logger';
import { IAgedValue, IAgedQueue } from '../queue/IAgedQueue';
import { AgingCacheWriteStatus, IAgingCacheWrite } from './IAgingCache';
import { IStorageHierarchy, IStorageHierarchyWrite } from '../storage/IStorageHierarchy';
 
/**
 * Keep common methods and data for each set/delete strategy here
 */
export abstract class AgingCacheWriteStrategy<TKey, TValue> {
  protected readonly logger = Logger.get(AgingCacheWriteStrategy.name);
 
  /**
   * @param hierarchy The storage hierarchy to operate on
   * @param evictQueue The keys in the order to evict
   */
  constructor(
    protected readonly hierarchy: IStorageHierarchy<TKey, TValue>,
    protected readonly evictQueue: IAgedQueue<TKey>
  ) {}
 
  protected executeDelete = (key: TKey, level?: number): Promise<IAgingCacheWrite<TValue>> => {
    return this.hierarchy.deleteAtLevel(key, level).then(status => {
      const write = this.getWriteStatus(status, level);
      Iif (write.status === AgingCacheWriteStatus.Success) {
        this.evictQueue.delete(key);
      }
 
      return write;
    });
  };
 
  protected executeSet = (
    key: TKey,
    value: TValue,
    level?: number
  ): Promise<IAgingCacheWrite<TValue>> => {
    const agedValue = {
      age: this.evictQueue.getInitialAge(key),
      value,
    };
    return this.hierarchy.setAtLevel(key, agedValue, level).then(status => {
      const write = this.getWriteStatus(status, level);
      Iif (write.status === AgingCacheWriteStatus.Success) {
        this.evictQueue.addOrReplace(key, agedValue.age);
      }
 
      return write;
    });
  };
 
  protected setFromHighestLevel = (
    key: TKey,
    agedValue: IAgedValue<TValue>
  ): Promise<IAgingCacheWrite<TValue>> => {
    return this.hierarchy.setBelowTopLevel(key, agedValue).then(status => {
      Iif (status.writtenLevels === this.hierarchy.totalLevels - 1) {
        this.evictQueue.addOrReplace(key, agedValue.age);
        return Promise.resolve<IAgingCacheWrite<TValue>>({
          status: AgingCacheWriteStatus.Refreshed,
          value: status.writtenValue?.value,
        });
      }
 
      return Promise.resolve({
        status: AgingCacheWriteStatus.RefreshedError,
        value: status.writtenValue?.value,
      });
    });
  };
 
  protected getWriteStatus(
    status: IStorageHierarchyWrite<TValue>,
    level?: number
  ): IAgingCacheWrite<TValue> {
    const expectedWritten = level ? level + 1 : this.hierarchy.totalLevels;
    return {
      status:
        status.writtenLevels === expectedWritten
          ? AgingCacheWriteStatus.Success
          : status.writtenLevels === 0
          ? AgingCacheWriteStatus.UnspecifiedError
          : AgingCacheWriteStatus.PartialWrite,
      value: status.writtenValue?.value,
    };
  }
}