request-context-cache.service.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { RequestContext } from '../api';
  2. /**
  3. * @description
  4. * This service is used to cache arbitrary data relative to an ongoing request.
  5. * It does this by using a WeakMap bound to the current RequestContext, so the cached
  6. * data is available for the duration of the request. Once the request completes, the
  7. * cached data will be automatically garbage-collected.
  8. *
  9. * This is useful for caching data which is expensive to compute and which is needed
  10. * multiple times during the handling of a single request.
  11. *
  12. * @docsCategory cache
  13. */
  14. export class RequestContextCacheService {
  15. private caches = new WeakMap<RequestContext, Map<any, any>>();
  16. /**
  17. * @description
  18. * Set a value in the RequestContext cache.
  19. */
  20. set<T = any>(ctx: RequestContext, key: any, val: T): void {
  21. this.getContextCache(ctx).set(key, val);
  22. }
  23. /**
  24. * @description
  25. * Get a value from the RequestContext cache. If the value is not found, the `getDefault`
  26. * function will be called to get the value, which will then be cached and returned.
  27. */
  28. get<T = any>(ctx: RequestContext, key: any): T | undefined;
  29. get<T>(ctx: RequestContext, key: any, getDefault?: () => T): T;
  30. get<T>(ctx: RequestContext, key: any, getDefault?: () => T): T | Promise<T> | undefined {
  31. const ctxCache = this.getContextCache(ctx);
  32. const result = ctxCache.get(key);
  33. if (result) {
  34. return result;
  35. }
  36. if (getDefault) {
  37. const defaultResultOrPromise = getDefault();
  38. ctxCache.set(key, defaultResultOrPromise);
  39. return defaultResultOrPromise;
  40. } else {
  41. return;
  42. }
  43. }
  44. private getContextCache(ctx: RequestContext): Map<any, any> {
  45. let ctxCache = this.caches.get(ctx);
  46. if (!ctxCache) {
  47. ctxCache = new Map<any, any>();
  48. this.caches.set(ctx, ctxCache);
  49. }
  50. return ctxCache;
  51. }
  52. private isPromise<T>(input: T | Promise<T>): input is Promise<T> {
  53. return typeof (input as any).then === 'function';
  54. }
  55. }