UNPKG

typesense

Version:
106 lines (93 loc) 3.33 kB
const defaultCacheResponseForSeconds = 2 * 60; const defaultMaxSize = 100; export default class RequestWithCache { private responseCache: Map<string, any> = new Map<string, any>(); private responsePromiseCache: Map<string, any> = new Map<string, any>(); clearCache() { this.responseCache = new Map<string, any>(); this.responsePromiseCache = new Map<string, any>(); } // Todo: should probably be passed a callback instead, or an apiCall instance. Types are messy this way async perform<T>( requestContext: any, requestFunction: (...params: any) => unknown, requestFunctionArguments: any[], cacheOptions: CacheOptions ): Promise<T | unknown> { const { cacheResponseForSeconds = defaultCacheResponseForSeconds, maxSize = defaultMaxSize, } = cacheOptions; const isCacheDisabled = cacheResponseForSeconds <= 0 || maxSize <= 0; if (isCacheDisabled) { return requestFunction.call(requestContext, ...requestFunctionArguments); } const requestFunctionArgumentsJSON = JSON.stringify( requestFunctionArguments ); const cacheEntry = this.responseCache.get(requestFunctionArgumentsJSON); const now = Date.now(); if (cacheEntry) { const isEntryValid = now - cacheEntry.requestTimestamp < cacheResponseForSeconds * 1000; if (isEntryValid) { this.responseCache.delete(requestFunctionArgumentsJSON); this.responseCache.set(requestFunctionArgumentsJSON, cacheEntry); return Promise.resolve(cacheEntry.response); } else { this.responseCache.delete(requestFunctionArgumentsJSON); } } const cachePromiseEntry = this.responsePromiseCache.get( requestFunctionArgumentsJSON ); if (cachePromiseEntry) { const isEntryValid = now - cachePromiseEntry.requestTimestamp < cacheResponseForSeconds * 1000; if (isEntryValid) { this.responsePromiseCache.delete(requestFunctionArgumentsJSON); this.responsePromiseCache.set( requestFunctionArgumentsJSON, cachePromiseEntry ); return cachePromiseEntry.responsePromise; } else { this.responsePromiseCache.delete(requestFunctionArgumentsJSON); } } const responsePromise = requestFunction.call( requestContext, ...requestFunctionArguments ); this.responsePromiseCache.set(requestFunctionArgumentsJSON, { requestTimestamp: now, responsePromise, }); const response = await responsePromise; this.responseCache.set(requestFunctionArgumentsJSON, { requestTimestamp: now, response, }); const isCacheOverMaxSize = this.responseCache.size > maxSize; if (isCacheOverMaxSize) { const oldestEntry = this.responseCache.keys().next().value; if (oldestEntry) { this.responseCache.delete(oldestEntry); } } const isResponsePromiseCacheOverMaxSize = this.responsePromiseCache.size > maxSize; if (isResponsePromiseCacheOverMaxSize) { const oldestEntry = this.responsePromiseCache.keys().next().value; if (oldestEntry) { this.responsePromiseCache.delete(oldestEntry); } } return response as T; } } interface CacheOptions { cacheResponseForSeconds?: number; maxSize?: number; }