33/* eslint-disable @typescript-eslint/no-explicit-any */
44
55import _ from 'lodash' ;
6- import {
7- type Cache , caching , type Store ,
8- } from 'cache-manager' ;
6+ import { type Cache , caching , type Store } from 'cache-manager' ;
97import {
108 type CachedFunctionInitializerOptions , type CachedFunctionOptions , type CacheableFunction , type ArgumentPaths ,
11- Logger ,
9+ type Logger ,
10+ type CachedFunctionResult ,
1211} from './index.d' ;
1312
1413let cache : Cache | undefined ;
1514let logger : Logger = {
16- info ( ...args : any ) { } ,
17- debug ( ...args : any ) { } ,
18- trace ( ...args : any ) { } ,
19- warn ( ...args : any ) { } ,
20- error ( ...args : any ) { } ,
15+ info ( ...arguments_ : any ) { } , // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
16+ debug ( ...arguments_ : any ) { } , // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
17+ trace ( ...arguments_ : any ) { } , // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
18+ warn ( ...arguments_ : any ) { } , // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
19+ error ( ...arguments_ : any ) { } , // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
2120} ;
2221
2322/**
@@ -41,9 +40,9 @@ export async function getOrInitializeCache<S extends Store>(options?: CachedFunc
4140 logger = options . logger as Logger ;
4241 }
4342
44- logger ? .trace ( 'Initializing cache' ) ;
43+ logger . trace ( 'Initializing cache' ) ;
4544 cache ||= await ( 'config' in options ! ? caching ( options . store , options . config ) : caching ( options ! . store ) ) ;
46- logger ? .trace ( 'Cache initialized' ) ;
45+ logger . trace ( 'Cache initialized' ) ;
4746
4847 return cache as Cache < S > ;
4948}
@@ -53,7 +52,7 @@ export async function getOrInitializeCache<S extends Store>(options?: CachedFunc
5352 */
5453export function resetCache ( ) {
5554 cache = undefined ;
56- logger ? .warn ( 'You have called resetCache, which is deprecated and basically does nothing. To close any open connections, please retrieve the cache object from getOrInitializeCache and close it directly.' ) ;
55+ logger . warn ( 'You have called resetCache, which is deprecated and basically does nothing. To close any open connections, please retrieve the cache object from getOrInitializeCache and close it directly.' ) ;
5756}
5857
5958/**
@@ -66,10 +65,10 @@ export function resetCache() {
6665 * @throws {Error } If a path in the selector does not exist in the provided arguments.
6766 * @throws {TypeError } If a path in the selector points to a function, which is not serializable.
6867 */
69- export function selectorToCacheKey < F extends CacheableFunction > ( arguments_ : Parameters < F > , selector : ArgumentPaths < F > ) {
68+ export function selectorToCacheKey < F extends CacheableFunction > ( arguments_ : Parameters < F > , selector : ArgumentPaths < F > , namespace ?: string ) : string {
7069 const selectors = _ . castArray ( selector ) ;
7170 if ( selectors . length === 0 ) {
72- logger ? .trace ( arguments_ , 'No selectors provided, using the entire arguments object as the cache key' ) ;
71+ logger . trace ( arguments_ , 'No selectors provided, using the entire arguments object as the cache key' ) ;
7372 return JSON . stringify ( arguments_ ) ;
7473 }
7574
@@ -85,7 +84,12 @@ export function selectorToCacheKey<F extends CacheableFunction>(arguments_: Para
8584
8685 return value ;
8786 } ) ;
87+
8888 const result = _ . zipObject ( selectors , values ) ;
89+ if ( namespace ) {
90+ result . namespace = namespace ;
91+ }
92+
8993 return JSON . stringify ( result ) ;
9094}
9195
@@ -99,34 +103,64 @@ export function selectorToCacheKey<F extends CacheableFunction>(arguments_: Para
99103 * @returns A promise that resolves to the result of the function.
100104 */
101105export function cachedFunction < F extends CacheableFunction > ( function_ : F , options ?: CachedFunctionOptions < F > ) {
102- return async ( ...arguments_ : Parameters < F > ) : Promise < ReturnType < F > > => {
106+ return async ( ...arguments_ : Parameters < F > ) : Promise < ReturnType < F > | CachedFunctionResult < ReturnType < F > > > => {
103107 const cacheOptions = _ . merge ( { } , options ?? { } , function_ . cacheOptions ?? { } ) ;
104108 if ( _ . keys ( cacheOptions ) . length === 0 ) {
105109 throw new Error ( 'No cache options provided, either use the @CacheOptions decorator or provide options to cachedFunction directly.' ) ;
106110 }
107111
108- if ( ! cacheOptions . noCache ) {
109- logger . trace ( 'Cache is disabled, calling the original function directly' ) ;
112+ if ( cacheOptions . noCache && cacheOptions . returnRawValue ) {
113+ logger . trace ( 'Cache is disabled via `noCache=true`. Calling the original function directly and returning the raw value ' ) ;
110114 return function_ ( ...arguments_ ) as ReturnType < F > ;
111115 }
112116
117+ if ( cacheOptions . noCache && ! cacheOptions . returnRawValue ) {
118+ logger . trace ( 'Cache is disabled via `noCache=true`. Calling the original function directly and returning a `CachedFunctionResult` object' ) ;
119+ return {
120+ result : function_ ( ...arguments_ ) as ReturnType < F > ,
121+ created : false ,
122+ options : cacheOptions ,
123+ } ;
124+ }
125+
113126 const cacheKey = selectorToCacheKey ( arguments_ , cacheOptions . selector ! ) ;
114127 const cache = await getOrInitializeCache ( options as CachedFunctionInitializerOptions ) ;
115128
116- logger ? .trace ( { cacheKey} , 'Checking cache' ) ;
129+ logger . trace ( { cacheKey} , 'Checking cache' ) ;
117130 const cacheValue = await cache . get < ReturnType < F > > ( cacheKey ) ;
118- if ( ! cacheOptions . force && cacheValue !== undefined ) {
119- logger ? .trace ( { cacheKey} , 'Cache hit' ) ;
131+ if ( ! cacheOptions . force && ! _ . isNil ( cacheValue ) && cacheOptions . returnRawValue ) {
132+ logger . trace ( { cacheKey} , 'Cache hit' ) ;
120133 return cacheValue ;
121134 }
122- logger ?. trace ( { cacheKey} , 'Cache miss' ) ;
123135
136+ if ( ! cacheOptions . force && ! _ . isNil ( cacheValue ) && ! cacheOptions . returnRawValue ) {
137+ logger . trace ( { cacheKey} , 'Cache hit' ) ;
138+ return {
139+ key : cacheKey ,
140+ result : cacheValue ,
141+ status : 'hit' ,
142+ created : false ,
143+ options : cacheOptions ,
144+ } ;
145+ }
146+
147+ logger . trace ( { cacheKey} , 'Cache miss' ) ;
124148 const result = await function_ ( ...arguments_ ) as ReturnType < F > ;
125- logger ? .trace ( { cacheKey} , 'Setting cache' ) ;
149+ logger . trace ( { cacheKey} , 'Setting cache' ) ;
126150 await cache . set ( cacheKey , result , cacheOptions . ttl ) ;
127- logger ?. trace ( { cacheKey} , 'Cache set' ) ;
151+ logger . trace ( { cacheKey} , 'Cache set' ) ;
152+
153+ if ( cacheOptions . returnRawValue ) {
154+ return result ;
155+ }
128156
129- return result ;
157+ return {
158+ key : cacheKey ,
159+ result,
160+ status : 'miss' ,
161+ created : true ,
162+ options : cacheOptions ,
163+ } ;
130164 } ;
131165}
132166
@@ -169,7 +203,7 @@ export function CacheOptions<F extends CacheableFunction>(
169203 descriptor : TypedPropertyDescriptor < F > ,
170204 ) : any => {
171205 if ( ! descriptor . value ) {
172- logger ? .warn ( 'CacheOptions decorator is only supported on methods' ) ;
206+ logger . warn ( 'CacheOptions decorator is only supported on methods' ) ;
173207 return ;
174208 }
175209
0 commit comments