src/cache/decorators/Cached.ts   A
last analyzed

Complexity

Total Complexity 4
Complexity/F 4

Size

Lines of Code 61
Function Count 1

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 4
eloc 46
mnd 3
bc 3
fnc 1
dl 0
loc 61
ccs 26
cts 26
cp 1
rs 10
bpm 3
cpm 4
noi 0
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A Cached.ts ➔ Cached 0 32 4
1 5
import { createHash } from 'node:crypto';
2
import { Cache } from '@/ExpressBeansTypes';
3 5
import { logger, registeredMethods } from '@/core';
4
5
type BeanFunction = (...args: any) => any
6
type CacheEntry = {
7
  data: ReturnType<BeanFunction>,
8
  expiration: number,
9
}
10
11 8
const createKey = (obj: any) => createHash('sha224')
12
  .update(JSON.stringify(obj))
13
  .digest('hex');
14
15 5
const getCachedData = (cache: Map<string, CacheEntry>, key: string) => {
16 8
  const cached = cache.get(key);
17 8
  if (!cached) {
18 4
    throw new Error(`Key ${key} not found in cache`);
19
  }
20 4
  if (cached.expiration < Date.now()) {
21 1
    cache.delete(key);
22 1
    throw new Error(`Key ${key} expired in cache`);
23
  }
24 3
  return cached;
25
};
26
27
/**
28
 * Caches the result of a method
29
 * @param options {Cache}
30
 * @decorator
31
 */
32 5
export function Cached<This>(
33
  options: Cache = { duration: 60_000, type: 'memory' },
34
) {
35 3
  return (
36
    method: BeanFunction,
37
    context: ClassMethodDecoratorContext<This, BeanFunction>,
38
  ) => {
39 3
    logger.debug(`Initializing cache for method ${String(context.name)}`);
40 3
    const cache = new Map<string, CacheEntry>();
41 3
    return (...args: any) => {
42 8
      const key = createKey(args);
43
      let result;
44 8
      try {
45 8
        result = getCachedData(cache, key);
46 3
        logger.debug(`Returning cached data for ${key}`);
47
      } catch (error) {
48 5
        logger.debug(error);
49 5
        const computed = method.bind(registeredMethods.get(method))(...args);
50 5
        cache.set(key, {
51
          data: computed,
52
          expiration: Date.now() + options.duration,
53
        });
54 5
        return computed;
55
      }
56 3
      logger.debug(result);
57 3
      return result.data;
58
    };
59
  };
60
}
61