NaturalCycles/js-lib

View on GitHub
src/decorators/memoFnAsync.ts

Summary

Maintainability
A
0 mins
Test Coverage
B
86%
import { MISS } from '../types'
import type { AsyncMemoOptions } from './asyncMemo.decorator'
import type { AsyncMemoCache } from './memo.util'
import { jsonMemoSerializer, MapMemoCache } from './memo.util'

export interface MemoizedAsyncFunction {
  cache: AsyncMemoCache
}

/**
 * @experimental
 */
export function _memoFnAsync<T extends (...args: any[]) => Promise<any>>(
  fn: T,
  opt: AsyncMemoOptions,
): T & MemoizedAsyncFunction {
  const {
    logger = console,
    cacheFactory = () => new MapMemoCache(),
    cacheKeyFn = jsonMemoSerializer,
  } = opt

  const cache = cacheFactory()

  const memoizedFn = async function (this: any, ...args: any[]): Promise<any> {
    const ctx = this
    const cacheKey = cacheKeyFn(args)
    let value: any

    try {
      value = await cache.get(cacheKey)
    } catch (err) {
      logger.error(err)
    }

    if (value !== MISS) {
      return value
    }

    value = await fn.apply(ctx, args)

    void (async () => {
      try {
        await cache.set(cacheKey, value)
      } catch (err) {
        logger.error(err)
      }
    })()

    return value
  }

  Object.assign(memoizedFn, { cache })
  return memoizedFn as T & MemoizedAsyncFunction
}