UNPKG

@rt_lite/api

Version:

An unoficial rotten tomatoes REST api

113 lines (83 loc) 2.48 kB
import { CacheAlgorithm } from '~/models/cache-algorithm.model'; import { CacheRecord } from '~/models/cache-record.model'; import type { ICacheOptions } from '~/models/cache-options.model'; import { time } from '~/utilities/time.utility'; export type ICache <T> = { has: (key: string) => boolean; get: (key: string) => T | null; set: (key: string, value: T) => T; delete: (key: string) => T | null; clear: () => void; }; export class Cache <T> implements ICache<T> { static readonly DEFAULT_OPTIONS: ICacheOptions = { algorithm: CacheAlgorithm.LRU, maxSize: Infinity, ttl: time(1).days }; readonly #algorithm: CacheAlgorithm; readonly #cache = new Map<string, CacheRecord<T>>(); readonly #maxSize: number; readonly #ttl: number; constructor ({ algorithm = Cache.DEFAULT_OPTIONS.algorithm, maxSize = Cache.DEFAULT_OPTIONS.maxSize, ttl = Cache.DEFAULT_OPTIONS.ttl }: Readonly<Partial<ICacheOptions>> = { ...Cache.DEFAULT_OPTIONS }) { this.#algorithm = algorithm; this.#maxSize = maxSize; this.#ttl = ttl; } has (key: string): boolean { return this.#cache.has(key); } get (key: string): T | null { const record = this.#cache.get(key); if (!record) return null; const now = Date.now(); if (now - record.modified.getTime() > this.#ttl) { this.#cache.delete(key); return null; } return record.contents; } set (key: string, value: Readonly<T>): T { const existingRecord = this.#cache.get(key); if (existingRecord) { existingRecord.contents = value; this.#cache.set(key, existingRecord); return value; } const record = new CacheRecord(value); this.#cache.set(key, record); this.#enforceMaxSize(); return value; } delete (key: string): T | null { const record = this.#cache.get(key); if (!record) return null; this.#cache.delete(key); return record.contents; } clear (): void { this.#cache.clear(); } #enforceMaxSize (): void { if (this.#cache.size <= this.#maxSize) return; const purgeLRU = (): void => { const oldestKey = [...this.#cache.entries()] // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types .sort(([, { read: readA }], [, { read: readB }]) => { if (readA > readB) return 1; if (readA < readB) return -1; return 0; })[0][0]; this.delete(oldestKey); }; switch (this.#algorithm) { case CacheAlgorithm.LRU: default: while (this.#cache.size > this.#maxSize) purgeLRU(); } } }