@jintianxiayu/cache-decorator 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -11
- package/README.md +364 -270
- package/dist/core/cache-error.d.ts +75 -0
- package/dist/core/cache-error.d.ts.map +1 -0
- package/dist/core/cache-error.js +168 -0
- package/dist/core/cache-error.js.map +1 -0
- package/dist/core/cache-logger.d.ts +3 -2
- package/dist/core/cache-logger.d.ts.map +1 -1
- package/dist/core/cache-logger.js +2 -0
- package/dist/core/cache-logger.js.map +1 -1
- package/dist/decorators/cache-evict.d.ts.map +1 -1
- package/dist/decorators/cache-evict.js +15 -10
- package/dist/decorators/cache-evict.js.map +1 -1
- package/dist/decorators/cache.d.ts +6 -0
- package/dist/decorators/cache.d.ts.map +1 -1
- package/dist/decorators/cache.js +113 -36
- package/dist/decorators/cache.js.map +1 -1
- package/jest.config.js +11 -11
- package/package.json +1 -1
- package/src/adapters/ioredis-cache-client.ts +89 -89
- package/src/adapters/node-redis-cache-client.ts +95 -95
- package/src/adapters/redis-key-prefix.ts +38 -38
- package/src/core/cache-error.ts +233 -0
- package/src/core/cache-logger.ts +116 -105
- package/src/core/key-builder.ts +33 -33
- package/src/core/native-cache.ts +55 -55
- package/src/core/pending-cache.ts +29 -29
- package/src/core/redis-cache-client.ts +160 -160
- package/src/core/redis-cache.ts +104 -104
- package/src/decorators/cache-evict.ts +137 -129
- package/src/decorators/cache.ts +323 -203
- package/src/index.ts +11 -11
- package/test/cache-evict-logging.test.ts +398 -362
- package/test/cache-logger.integration.test.ts +159 -129
- package/test/cache-logger.test.ts +156 -153
- package/test/cache-logging.test.ts +929 -544
- package/test/cache.test.ts +1017 -255
- package/test/fixtures/cache-logger-child.mjs +108 -108
- package/test/fixtures/cache-provider-failure-child.mjs +70 -0
- package/test/helpers/legacy-redis-cache.ts +41 -22
- package/test/helpers/package-consumer.ts +231 -231
- package/test/helpers/redis-fixture.ts +142 -142
- package/test/ioredis-cache-client.test.ts +143 -143
- package/test/legacy-redis-cache.test.ts +51 -0
- package/test/native-cache.test.ts +77 -77
- package/test/node-redis-cache-client.test.ts +149 -149
- package/test/pending-cache.test.ts +69 -69
- package/test/redis-cache-client-lifecycle.test.ts +112 -112
- package/test/redis-cache-client-types.test.ts +184 -184
- package/test/redis-cache-client.integration.test.ts +355 -327
- package/test/redis-cache-decorator.test.ts +601 -201
- package/test/redis-cache-provider.test.ts +269 -269
- package/test/type-contract/contract.ts +119 -64
- package/test/type-contract/tsconfig.json +12 -12
- package/tsconfig.json +8 -8
package/src/decorators/cache.ts
CHANGED
|
@@ -1,203 +1,323 @@
|
|
|
1
|
-
import 'reflect-metadata';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
interface
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
*
|
|
105
|
-
* @param
|
|
106
|
-
* @
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
logContext: CacheLogContext
|
|
112
|
-
):
|
|
113
|
-
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import {
|
|
3
|
+
decodeCacheError,
|
|
4
|
+
encodeCacheError,
|
|
5
|
+
isCurrentCacheErrorPayload,
|
|
6
|
+
normalizeCacheErrorPolicy,
|
|
7
|
+
type CacheErrorCodec,
|
|
8
|
+
type CacheErrorPolicy,
|
|
9
|
+
type NormalizedCacheErrorPolicy,
|
|
10
|
+
} from '../core/cache-error';
|
|
11
|
+
import { cacheProviderLabel, logCacheEvent, type CacheLogContext } from '../core/cache-logger';
|
|
12
|
+
import type { CacheProvider } from '../core/cache-provider';
|
|
13
|
+
import { CacheProviderRegistry } from '../core/cache-provider-registry';
|
|
14
|
+
import { KeyBuilder } from '../core/key-builder';
|
|
15
|
+
import { PendingCache } from '../core/pending-cache';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 缓存 key 解析器类型
|
|
19
|
+
* - null: 使用自动生成逻辑
|
|
20
|
+
* - string: 直接作为 key 值的一部分
|
|
21
|
+
* - function: 接收方法参数数组,返回自定义字符串
|
|
22
|
+
*/
|
|
23
|
+
export type CacheKeyResolver = null | string | ((...args: unknown[]) => string);
|
|
24
|
+
|
|
25
|
+
export type { CacheErrorCodec, CacheErrorPolicy };
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @Cache 装饰器配置项
|
|
29
|
+
*/
|
|
30
|
+
export interface CacheOptions {
|
|
31
|
+
/**
|
|
32
|
+
* 过期时间(秒)
|
|
33
|
+
*/
|
|
34
|
+
ttl?: number;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 指定 CacheProvider 名称
|
|
38
|
+
*/
|
|
39
|
+
providerName?: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 自定义缓存 key 生成逻辑
|
|
43
|
+
* - undefined/null: 使用默认逻辑 KeyBuilder.build(cacheName, args)
|
|
44
|
+
* - string: 使用 KeyBuilder.build(cacheName, [key])
|
|
45
|
+
* - function: 调用函数后使用 KeyBuilder.build(cacheName, [result])
|
|
46
|
+
*/
|
|
47
|
+
key?: CacheKeyResolver;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 业务异常缓存策略;省略时不向 Provider 持久化业务异常。
|
|
51
|
+
*/
|
|
52
|
+
errorCache?: CacheErrorPolicy;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 成功缓存条目
|
|
57
|
+
*/
|
|
58
|
+
interface SuccessCacheEntry<T> {
|
|
59
|
+
value: T;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 错误缓存条目
|
|
64
|
+
*/
|
|
65
|
+
interface ErrorCacheEntry {
|
|
66
|
+
error: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 缓存条目联合类型
|
|
71
|
+
*/
|
|
72
|
+
type CacheEntry<T> = SuccessCacheEntry<T> | ErrorCacheEntry;
|
|
73
|
+
|
|
74
|
+
interface CacheWriteRequest<T> {
|
|
75
|
+
readonly provider: CacheProvider;
|
|
76
|
+
readonly cacheKey: string;
|
|
77
|
+
readonly entry: CacheEntry<T>;
|
|
78
|
+
readonly entryType: 'value' | 'error';
|
|
79
|
+
readonly ttl: number | undefined;
|
|
80
|
+
readonly logContext: CacheLogContext;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type CacheLookupResult<T> =
|
|
84
|
+
| { readonly type: 'hit'; readonly provider: CacheProvider; readonly entry: CacheEntry<T> }
|
|
85
|
+
| { readonly type: 'miss'; readonly provider: CacheProvider }
|
|
86
|
+
| { readonly type: 'bypass' };
|
|
87
|
+
|
|
88
|
+
type CacheReadResult<T> =
|
|
89
|
+
| { readonly type: 'value'; readonly value: T }
|
|
90
|
+
| { readonly type: 'error'; readonly error: unknown }
|
|
91
|
+
| { readonly type: 'miss' };
|
|
92
|
+
|
|
93
|
+
interface BusinessErrorRequest {
|
|
94
|
+
readonly error: unknown;
|
|
95
|
+
readonly errorPolicy: NormalizedCacheErrorPolicy | undefined;
|
|
96
|
+
readonly provider: CacheProvider;
|
|
97
|
+
readonly cacheKey: string;
|
|
98
|
+
readonly logContext: CacheLogContext;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const pendingCache = new PendingCache();
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 获取配置指向的缓存 Provider,并把解析失败转换为缓存旁路。
|
|
105
|
+
* @param providerName decorator 配置中的 Provider 名称。
|
|
106
|
+
* @param logContext 当前方法的稳定日志上下文。
|
|
107
|
+
* @returns 已注册的缓存 Provider;解析失败时返回 undefined。
|
|
108
|
+
*/
|
|
109
|
+
function resolveCacheProvider(
|
|
110
|
+
providerName: string | undefined,
|
|
111
|
+
logContext: CacheLogContext
|
|
112
|
+
): CacheProvider | undefined {
|
|
113
|
+
try {
|
|
114
|
+
return CacheProviderRegistry.get(providerName);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
logCacheEvent('cache.operation_failed', { ...logContext, operation: 'provider_resolution', error });
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 保持 fire-and-forget 语义提交缓存写入,并消费同步或异步 Provider 失败。
|
|
123
|
+
* @param request 写入所需 Provider、entry 和无业务数据日志上下文。
|
|
124
|
+
* @returns 无返回值;写入失败仅记录日志,不影响业务结果。
|
|
125
|
+
*/
|
|
126
|
+
function dispatchCacheWrite<T>(request: CacheWriteRequest<T>): void {
|
|
127
|
+
let operation: void | Promise<void>;
|
|
128
|
+
try {
|
|
129
|
+
operation = request.provider.set(request.cacheKey, request.entry, request.ttl);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
logCacheEvent('cache.operation_failed', { ...request.logContext, operation: 'write', error });
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
logCacheEvent('cache.write_dispatched', { ...request.logContext, entryType: request.entryType });
|
|
135
|
+
void Promise.resolve(operation).catch((error: unknown) => {
|
|
136
|
+
logCacheEvent('cache.operation_failed', { ...request.logContext, operation: 'write', error });
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isErrorCacheEntry<T>(entry: CacheEntry<T>): entry is ErrorCacheEntry {
|
|
141
|
+
return typeof entry === 'object' && entry !== null && 'error' in entry;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 按当前异常策略分类 Provider 条目,并只把可成功解码的当前版本异常视为命中。
|
|
146
|
+
* @param entry Provider 返回的缓存联合条目。
|
|
147
|
+
* @param errorPolicy 当前装饰器归一化后的异常策略。
|
|
148
|
+
* @param logContext 当前方法的稳定日志上下文。
|
|
149
|
+
* @returns value/error 命中结果,或需要继续业务流程的 miss。
|
|
150
|
+
*/
|
|
151
|
+
function resolveCachedEntry<T>(
|
|
152
|
+
entry: CacheEntry<T>,
|
|
153
|
+
errorPolicy: NormalizedCacheErrorPolicy | undefined,
|
|
154
|
+
logContext: CacheLogContext
|
|
155
|
+
): CacheReadResult<T> {
|
|
156
|
+
if (!isErrorCacheEntry(entry)) {
|
|
157
|
+
logCacheEvent('cache.hit', { ...logContext, entryType: 'value' });
|
|
158
|
+
return { type: 'value', value: entry.value };
|
|
159
|
+
}
|
|
160
|
+
if (!isCurrentCacheErrorPayload(entry.error)) {
|
|
161
|
+
logCacheEvent('cache.error_cache_skipped', { ...logContext, reason: 'legacy_entry' });
|
|
162
|
+
return { type: 'miss' };
|
|
163
|
+
}
|
|
164
|
+
if (errorPolicy === undefined) {
|
|
165
|
+
logCacheEvent('cache.error_cache_skipped', { ...logContext, reason: 'disabled_entry' });
|
|
166
|
+
return { type: 'miss' };
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const error = decodeCacheError(entry.error, errorPolicy);
|
|
170
|
+
logCacheEvent('cache.hit', { ...logContext, entryType: 'error' });
|
|
171
|
+
return { type: 'error', error };
|
|
172
|
+
} catch (_error) {
|
|
173
|
+
logCacheEvent('cache.error_cache_failed', { ...logContext, phase: 'decode' });
|
|
174
|
+
return { type: 'miss' };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 按固定顺序评估筛选器、编码异常并发起独立 TTL 写入,任何策略失败都保留原业务异常。
|
|
180
|
+
* @param request 本次业务异常、当前策略、Provider、完整 key 与稳定日志上下文。
|
|
181
|
+
* @returns 无返回值。
|
|
182
|
+
*/
|
|
183
|
+
function handleBusinessError(request: BusinessErrorRequest): void {
|
|
184
|
+
const { error, errorPolicy, provider, cacheKey, logContext } = request;
|
|
185
|
+
if (errorPolicy === undefined) {
|
|
186
|
+
logCacheEvent('cache.error_cache_skipped', { ...logContext, reason: 'disabled' });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (errorPolicy.shouldCache !== undefined) {
|
|
190
|
+
let accepted: boolean;
|
|
191
|
+
try {
|
|
192
|
+
accepted = errorPolicy.shouldCache(error);
|
|
193
|
+
if (typeof accepted !== 'boolean') {
|
|
194
|
+
throw new TypeError('Cache error shouldCache must return a boolean');
|
|
195
|
+
}
|
|
196
|
+
} catch (_error) {
|
|
197
|
+
logCacheEvent('cache.error_cache_failed', { ...logContext, phase: 'predicate' });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!accepted) {
|
|
201
|
+
logCacheEvent('cache.error_cache_skipped', { ...logContext, reason: 'predicate_rejected' });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let entry: ErrorCacheEntry;
|
|
207
|
+
try {
|
|
208
|
+
entry = { error: encodeCacheError(error, errorPolicy) };
|
|
209
|
+
} catch (_error) {
|
|
210
|
+
logCacheEvent('cache.error_cache_failed', { ...logContext, phase: 'encode' });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
dispatchCacheWrite({ provider, cacheKey, entry, entryType: 'error', ttl: errorPolicy.ttl, logContext });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 解析缓存 key
|
|
218
|
+
* @param keyResolver key 解析器
|
|
219
|
+
* @param args 方法参数数组
|
|
220
|
+
* @param logContext 不包含业务参数和值的日志上下文
|
|
221
|
+
* @returns 解析后的缓存 key
|
|
222
|
+
*/
|
|
223
|
+
function resolveCacheKey(
|
|
224
|
+
keyResolver: CacheKeyResolver | undefined,
|
|
225
|
+
args: unknown[],
|
|
226
|
+
logContext: CacheLogContext
|
|
227
|
+
): string {
|
|
228
|
+
if (keyResolver === undefined || keyResolver === null) {
|
|
229
|
+
return KeyBuilder.build(logContext.cacheName, args);
|
|
230
|
+
}
|
|
231
|
+
if (typeof keyResolver === 'string') {
|
|
232
|
+
return KeyBuilder.build(logContext.cacheName, [keyResolver]);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
return KeyBuilder.build(logContext.cacheName, [keyResolver(...args)]);
|
|
236
|
+
} catch (_error) {
|
|
237
|
+
logCacheEvent('cache.key_fallback', { ...logContext, reason: 'resolver_error' });
|
|
238
|
+
return KeyBuilder.build(logContext.cacheName, args);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 缓存装饰器
|
|
244
|
+
* 为方法添加声明式缓存功能,支持 TTL 过期和请求合并
|
|
245
|
+
* @param cacheName 缓存名称
|
|
246
|
+
* @param options 配置项
|
|
247
|
+
*/
|
|
248
|
+
export function Cache(
|
|
249
|
+
cacheName: string,
|
|
250
|
+
options?: CacheOptions
|
|
251
|
+
): (_target: object, _propertyKey: string, descriptor: PropertyDescriptor) => void {
|
|
252
|
+
const errorPolicy = normalizeCacheErrorPolicy(options?.errorCache);
|
|
253
|
+
return function <T>(_target: object, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
254
|
+
const originalMethod = descriptor.value;
|
|
255
|
+
const logContext: CacheLogContext = {
|
|
256
|
+
cacheName,
|
|
257
|
+
methodName: propertyKey,
|
|
258
|
+
providerName: cacheProviderLabel(options?.providerName),
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
descriptor.value = function (...args: unknown[]): Promise<T> {
|
|
262
|
+
const cacheKey = resolveCacheKey(options?.key, args, logContext);
|
|
263
|
+
|
|
264
|
+
const pending = pendingCache.get<T>(cacheKey);
|
|
265
|
+
if (pending) {
|
|
266
|
+
logCacheEvent('cache.pending_hit', logContext);
|
|
267
|
+
return pending;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const promise = (async () => {
|
|
271
|
+
const provider = resolveCacheProvider(options?.providerName, logContext);
|
|
272
|
+
if (provider === undefined) {
|
|
273
|
+
return (await originalMethod.apply(this, args)) as T;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let lookupResult: CacheLookupResult<T>;
|
|
277
|
+
try {
|
|
278
|
+
const entry = await provider.get<CacheEntry<T>>(cacheKey);
|
|
279
|
+
lookupResult = entry === undefined ? { type: 'miss', provider } : { type: 'hit', provider, entry };
|
|
280
|
+
} catch (error) {
|
|
281
|
+
logCacheEvent('cache.operation_failed', { ...logContext, operation: 'read', error });
|
|
282
|
+
lookupResult = { type: 'bypass' };
|
|
283
|
+
}
|
|
284
|
+
if (lookupResult.type === 'bypass') {
|
|
285
|
+
return (await originalMethod.apply(this, args)) as T;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (lookupResult.type === 'hit') {
|
|
289
|
+
const cachedResult = resolveCachedEntry(lookupResult.entry, errorPolicy, logContext);
|
|
290
|
+
if (cachedResult.type === 'value') {
|
|
291
|
+
return cachedResult.value;
|
|
292
|
+
}
|
|
293
|
+
if (cachedResult.type === 'error') {
|
|
294
|
+
throw cachedResult.error;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
logCacheEvent('cache.miss', logContext);
|
|
298
|
+
|
|
299
|
+
let result: T;
|
|
300
|
+
try {
|
|
301
|
+
result = (await originalMethod.apply(this, args)) as T;
|
|
302
|
+
} catch (error) {
|
|
303
|
+
handleBusinessError({ error, errorPolicy, provider, cacheKey, logContext });
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
dispatchCacheWrite({
|
|
307
|
+
provider,
|
|
308
|
+
cacheKey,
|
|
309
|
+
entry: { value: result },
|
|
310
|
+
entryType: 'value',
|
|
311
|
+
ttl: options?.ttl,
|
|
312
|
+
logContext,
|
|
313
|
+
});
|
|
314
|
+
return result;
|
|
315
|
+
})();
|
|
316
|
+
|
|
317
|
+
pendingCache.set(cacheKey, promise);
|
|
318
|
+
return promise;
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export { CacheProviderRegistry } from '../core/cache-provider-registry';
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { createIoredisCacheClient } from './adapters/ioredis-cache-client';
|
|
2
|
-
export { createNodeRedisCacheClient } from './adapters/node-redis-cache-client';
|
|
3
|
-
export * from './core/cache-provider';
|
|
4
|
-
export * from './core/cache-provider-registry';
|
|
5
|
-
export * from './core/key-builder';
|
|
6
|
-
export * from './core/native-cache';
|
|
7
|
-
export * from './core/pending-cache';
|
|
8
|
-
export * from './core/redis-cache-client';
|
|
9
|
-
export * from './core/redis-cache';
|
|
10
|
-
export * from './decorators/cache';
|
|
11
|
-
export * from './decorators/cache-evict';
|
|
1
|
+
export { createIoredisCacheClient } from './adapters/ioredis-cache-client';
|
|
2
|
+
export { createNodeRedisCacheClient } from './adapters/node-redis-cache-client';
|
|
3
|
+
export * from './core/cache-provider';
|
|
4
|
+
export * from './core/cache-provider-registry';
|
|
5
|
+
export * from './core/key-builder';
|
|
6
|
+
export * from './core/native-cache';
|
|
7
|
+
export * from './core/pending-cache';
|
|
8
|
+
export * from './core/redis-cache-client';
|
|
9
|
+
export * from './core/redis-cache';
|
|
10
|
+
export * from './decorators/cache';
|
|
11
|
+
export * from './decorators/cache-evict';
|