3
3
/* eslint-disable @typescript-eslint/no-explicit-any */
4
4
5
5
import _ from 'lodash' ;
6
- import {
7
- type Cache , caching , type Store ,
8
- } from 'cache-manager' ;
6
+ import { type Cache , caching , type Store } from 'cache-manager' ;
9
7
import {
10
8
type CachedFunctionInitializerOptions , type CachedFunctionOptions , type CacheableFunction , type ArgumentPaths ,
11
- Logger ,
9
+ type Logger ,
10
+ type CachedFunctionResult ,
12
11
} from './index.d' ;
13
12
14
13
let cache : Cache | undefined ;
15
14
let 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
21
20
} ;
22
21
23
22
/**
@@ -41,9 +40,9 @@ export async function getOrInitializeCache<S extends Store>(options?: CachedFunc
41
40
logger = options . logger as Logger ;
42
41
}
43
42
44
- logger ? .trace ( 'Initializing cache' ) ;
43
+ logger . trace ( 'Initializing cache' ) ;
45
44
cache ||= await ( 'config' in options ! ? caching ( options . store , options . config ) : caching ( options ! . store ) ) ;
46
- logger ? .trace ( 'Cache initialized' ) ;
45
+ logger . trace ( 'Cache initialized' ) ;
47
46
48
47
return cache as Cache < S > ;
49
48
}
@@ -53,7 +52,7 @@ export async function getOrInitializeCache<S extends Store>(options?: CachedFunc
53
52
*/
54
53
export function resetCache ( ) {
55
54
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.' ) ;
57
56
}
58
57
59
58
/**
@@ -66,10 +65,10 @@ export function resetCache() {
66
65
* @throws {Error } If a path in the selector does not exist in the provided arguments.
67
66
* @throws {TypeError } If a path in the selector points to a function, which is not serializable.
68
67
*/
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 {
70
69
const selectors = _ . castArray ( selector ) ;
71
70
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' ) ;
73
72
return JSON . stringify ( arguments_ ) ;
74
73
}
75
74
@@ -85,7 +84,12 @@ export function selectorToCacheKey<F extends CacheableFunction>(arguments_: Para
85
84
86
85
return value ;
87
86
} ) ;
87
+
88
88
const result = _ . zipObject ( selectors , values ) ;
89
+ if ( namespace ) {
90
+ result . namespace = namespace ;
91
+ }
92
+
89
93
return JSON . stringify ( result ) ;
90
94
}
91
95
@@ -99,34 +103,64 @@ export function selectorToCacheKey<F extends CacheableFunction>(arguments_: Para
99
103
* @returns A promise that resolves to the result of the function.
100
104
*/
101
105
export 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 > > > => {
103
107
const cacheOptions = _ . merge ( { } , options ?? { } , function_ . cacheOptions ?? { } ) ;
104
108
if ( _ . keys ( cacheOptions ) . length === 0 ) {
105
109
throw new Error ( 'No cache options provided, either use the @CacheOptions decorator or provide options to cachedFunction directly.' ) ;
106
110
}
107
111
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 ' ) ;
110
114
return function_ ( ...arguments_ ) as ReturnType < F > ;
111
115
}
112
116
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
+
113
126
const cacheKey = selectorToCacheKey ( arguments_ , cacheOptions . selector ! ) ;
114
127
const cache = await getOrInitializeCache ( options as CachedFunctionInitializerOptions ) ;
115
128
116
- logger ? .trace ( { cacheKey} , 'Checking cache' ) ;
129
+ logger . trace ( { cacheKey} , 'Checking cache' ) ;
117
130
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' ) ;
120
133
return cacheValue ;
121
134
}
122
- logger ?. trace ( { cacheKey} , 'Cache miss' ) ;
123
135
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' ) ;
124
148
const result = await function_ ( ...arguments_ ) as ReturnType < F > ;
125
- logger ? .trace ( { cacheKey} , 'Setting cache' ) ;
149
+ logger . trace ( { cacheKey} , 'Setting cache' ) ;
126
150
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
+ }
128
156
129
- return result ;
157
+ return {
158
+ key : cacheKey ,
159
+ result,
160
+ status : 'miss' ,
161
+ created : true ,
162
+ options : cacheOptions ,
163
+ } ;
130
164
} ;
131
165
}
132
166
@@ -169,7 +203,7 @@ export function CacheOptions<F extends CacheableFunction>(
169
203
descriptor : TypedPropertyDescriptor < F > ,
170
204
) : any => {
171
205
if ( ! descriptor . value ) {
172
- logger ? .warn ( 'CacheOptions decorator is only supported on methods' ) ;
206
+ logger . warn ( 'CacheOptions decorator is only supported on methods' ) ;
173
207
return ;
174
208
}
175
209
0 commit comments