aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/datasource/cache.ts
blob: ecd74cbe79e1764bbf11c59c30366a05dd5bb694 (plain)
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
import { logger } from '../logger';
import * as globalCache from '../util/cache/global';

/**
 * Cache callback result which has to be returned by the `CacheCallback` function.
 */
export interface CacheResult<TResult = unknown> {
  /**
   * The data which should be added to the cache
   */
  data: TResult;
  /**
   * `data` can only be cached if this is not `true`
   */
  isPrivate?: boolean;
}

/**
 * Simple helper type for defining the `CacheCallback` function return type
 */
export type CachePromise<TResult = unknown> = Promise<CacheResult<TResult>>;

/**
 * The callback function which is called on cache miss.
 */
export type CacheCallback<TArg, TResult = unknown> = (
  lookup: TArg
) => CachePromise<TResult>;

export type CacheConfig<TArg, TResult> = {
  /**
   * Datasource id
   */
  id: string;
  /**
   * Cache key
   */
  lookup: TArg;
  /**
   * Callback to use on cache miss to load result
   */
  cb: CacheCallback<TArg, TResult>;
  /**
   * Time to cache result in minutes
   */
  minutes?: number;
};

/**
 * Loads result from cache or from passed callback on cache miss.
 * @param param0 Cache config args
 */
export async function cacheAble<TArg, TResult = unknown>({
  id,
  lookup,
  cb,
  minutes = 60,
}: CacheConfig<TArg, TResult>): Promise<TResult> {
  const cacheNamespace = `datasource-${id}`;
  const cacheKey = JSON.stringify(lookup);
  const cachedResult = await globalCache.get<TResult>(cacheNamespace, cacheKey);
  // istanbul ignore if
  if (cachedResult) {
    logger.trace({ id, lookup }, 'datasource cachedResult');
    return cachedResult;
  }
  const { data, isPrivate } = await cb(lookup);
  // istanbul ignore if
  if (isPrivate) {
    logger.trace({ id, lookup }, 'Skipping datasource cache for private data');
  } else {
    await globalCache.set(cacheNamespace, cacheKey, data, minutes);
  }
  return data;
}