@jintianxiayu/cache-decorator 1.0.0 → 1.0.1

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +20 -14
  2. package/README.md +358 -270
  3. package/dist/core/cache-error.d.ts +75 -0
  4. package/dist/core/cache-error.d.ts.map +1 -0
  5. package/dist/core/cache-error.js +168 -0
  6. package/dist/core/cache-error.js.map +1 -0
  7. package/dist/core/cache-logger.d.ts +3 -2
  8. package/dist/core/cache-logger.d.ts.map +1 -1
  9. package/dist/core/cache-logger.js +2 -0
  10. package/dist/core/cache-logger.js.map +1 -1
  11. package/dist/decorators/cache.d.ts +6 -0
  12. package/dist/decorators/cache.d.ts.map +1 -1
  13. package/dist/decorators/cache.js +106 -23
  14. package/dist/decorators/cache.js.map +1 -1
  15. package/jest.config.js +11 -11
  16. package/package.json +1 -1
  17. package/src/adapters/ioredis-cache-client.ts +89 -89
  18. package/src/adapters/node-redis-cache-client.ts +95 -95
  19. package/src/adapters/redis-key-prefix.ts +38 -38
  20. package/src/core/cache-error.ts +233 -0
  21. package/src/core/cache-logger.ts +116 -105
  22. package/src/core/key-builder.ts +33 -33
  23. package/src/core/native-cache.ts +55 -55
  24. package/src/core/pending-cache.ts +29 -29
  25. package/src/core/redis-cache-client.ts +160 -160
  26. package/src/core/redis-cache.ts +104 -104
  27. package/src/decorators/cache-evict.ts +129 -129
  28. package/src/decorators/cache.ts +319 -203
  29. package/src/index.ts +11 -11
  30. package/test/cache-evict-logging.test.ts +362 -362
  31. package/test/cache-logger.integration.test.ts +129 -129
  32. package/test/cache-logger.test.ts +156 -153
  33. package/test/cache-logging.test.ts +852 -544
  34. package/test/cache.test.ts +939 -255
  35. package/test/helpers/legacy-redis-cache.ts +41 -22
  36. package/test/helpers/package-consumer.ts +231 -231
  37. package/test/helpers/redis-fixture.ts +142 -142
  38. package/test/ioredis-cache-client.test.ts +143 -143
  39. package/test/legacy-redis-cache.test.ts +51 -0
  40. package/test/native-cache.test.ts +77 -77
  41. package/test/node-redis-cache-client.test.ts +149 -149
  42. package/test/pending-cache.test.ts +69 -69
  43. package/test/redis-cache-client-lifecycle.test.ts +112 -112
  44. package/test/redis-cache-client-types.test.ts +184 -184
  45. package/test/redis-cache-client.integration.test.ts +355 -327
  46. package/test/redis-cache-decorator.test.ts +540 -201
  47. package/test/redis-cache-provider.test.ts +269 -269
  48. package/test/type-contract/contract.ts +119 -64
  49. package/test/type-contract/tsconfig.json +12 -12
  50. package/tsconfig.json +8 -8
@@ -1,129 +1,129 @@
1
- import { cacheProviderLabel, logCacheEvent, type CacheLogContext } from '../core/cache-logger';
2
- import type { CacheProvider } from '../core/cache-provider';
3
- import { CacheProviderRegistry } from '../core/cache-provider-registry';
4
- import { KeyBuilder } from '../core/key-builder';
5
- import type { CacheKeyResolver, CacheOptions } from './cache';
6
-
7
- /**
8
- * @CacheEvict 装饰器配置项
9
- */
10
- export interface CacheEvictOptions extends Pick<CacheOptions, 'key'> {
11
- /**
12
- * 是否清除所有条目,默认为 false
13
- */
14
- allEntries?: boolean;
15
-
16
- /**
17
- * 指定 CacheProvider 名称
18
- */
19
- providerName?: string;
20
- }
21
-
22
- /**
23
- * 解析缓存 key
24
- * @param keyResolver key 解析器
25
- * @param args 方法参数数组
26
- * @param logContext 不包含业务参数和值的日志上下文
27
- * @returns 解析后的缓存 key
28
- */
29
- function resolveCacheKey(
30
- keyResolver: CacheKeyResolver | undefined,
31
- args: unknown[],
32
- logContext: CacheLogContext
33
- ): string {
34
- if (keyResolver === undefined || keyResolver === null) {
35
- return KeyBuilder.build(logContext.cacheName, args);
36
- }
37
- if (typeof keyResolver === 'string') {
38
- return KeyBuilder.build(logContext.cacheName, [keyResolver]);
39
- }
40
- try {
41
- return KeyBuilder.build(logContext.cacheName, [keyResolver(...args)]);
42
- } catch (_error) {
43
- logCacheEvent('cache.key_fallback', { ...logContext, reason: 'resolver_error' });
44
- return KeyBuilder.build(logContext.cacheName, args);
45
- }
46
- }
47
-
48
- /**
49
- * 获取淘汰操作使用的 Provider,并在解析失败时记录原始注册表错误。
50
- * @param providerName decorator 配置中的 Provider 名称。
51
- * @param logContext 当前方法的稳定日志上下文。
52
- * @returns 已注册的缓存 Provider。
53
- * @throws Provider 注册表抛出的原始错误。
54
- */
55
- function resolveCacheProvider(providerName: string | undefined, logContext: CacheLogContext): CacheProvider {
56
- try {
57
- return CacheProviderRegistry.get(providerName);
58
- } catch (error) {
59
- logCacheEvent('cache.operation_failed', { ...logContext, operation: 'provider_resolution', error });
60
- throw error;
61
- }
62
- }
63
-
64
- /**
65
- * 保持 fire-and-forget 语义发起单 key 删除,只处理调用当下可观察的同步失败。
66
- * @param provider 当前淘汰使用的 Provider。
67
- * @param cacheKey 待删除的完整 key;不会进入日志元数据。
68
- * @param logContext 当前方法的稳定日志上下文。
69
- * @returns 无返回值;异步删除 Promise 不会被等待或消费。
70
- * @throws Provider delete 同步抛出的原始错误。
71
- */
72
- function dispatchCacheDelete(provider: CacheProvider, cacheKey: string, logContext: CacheLogContext): void {
73
- try {
74
- provider.delete(cacheKey);
75
- } catch (error) {
76
- logCacheEvent('cache.operation_failed', { ...logContext, operation: 'evict', error });
77
- throw error;
78
- }
79
- logCacheEvent('cache.evict_dispatched', { ...logContext, scope: 'key' });
80
- }
81
-
82
- /**
83
- * 缓存清除装饰器
84
- * 在方法执行后清除对应的缓存条目
85
- * @param cacheName 缓存名称
86
- * @param options 配置项
87
- */
88
- export function CacheEvict(
89
- cacheName: string,
90
- options?: CacheEvictOptions
91
- ): (_target: object, _propertyKey: string, descriptor: PropertyDescriptor) => void {
92
- return function (_target: object, propertyKey: string, descriptor: PropertyDescriptor) {
93
- const originalMethod = descriptor.value;
94
- const logContext: CacheLogContext = {
95
- cacheName,
96
- methodName: propertyKey,
97
- providerName: cacheProviderLabel(options?.providerName),
98
- };
99
-
100
- descriptor.value = async function (...args: unknown[]) {
101
- let result: unknown;
102
- try {
103
- result = await originalMethod.apply(this, args);
104
- } catch (error) {
105
- logCacheEvent('cache.evict_skipped', { ...logContext, reason: 'business_error' });
106
- throw error;
107
- }
108
-
109
- const provider = resolveCacheProvider(options?.providerName, logContext);
110
-
111
- if (options?.allEntries) {
112
- try {
113
- await provider.deleteByPattern(cacheName + '*');
114
- } catch (error) {
115
- logCacheEvent('cache.operation_failed', { ...logContext, operation: 'evict', error });
116
- throw error;
117
- }
118
- logCacheEvent('cache.evict_completed', { ...logContext, scope: 'allEntries' });
119
- } else {
120
- const cacheKey = resolveCacheKey(options?.key, args, logContext);
121
- dispatchCacheDelete(provider, cacheKey, logContext);
122
- }
123
-
124
- return result;
125
- };
126
- };
127
- }
128
-
129
- export { CacheProviderRegistry } from '../core/cache-provider-registry';
1
+ import { cacheProviderLabel, logCacheEvent, type CacheLogContext } from '../core/cache-logger';
2
+ import type { CacheProvider } from '../core/cache-provider';
3
+ import { CacheProviderRegistry } from '../core/cache-provider-registry';
4
+ import { KeyBuilder } from '../core/key-builder';
5
+ import type { CacheKeyResolver, CacheOptions } from './cache';
6
+
7
+ /**
8
+ * @CacheEvict 装饰器配置项
9
+ */
10
+ export interface CacheEvictOptions extends Pick<CacheOptions, 'key'> {
11
+ /**
12
+ * 是否清除所有条目,默认为 false
13
+ */
14
+ allEntries?: boolean;
15
+
16
+ /**
17
+ * 指定 CacheProvider 名称
18
+ */
19
+ providerName?: string;
20
+ }
21
+
22
+ /**
23
+ * 解析缓存 key
24
+ * @param keyResolver key 解析器
25
+ * @param args 方法参数数组
26
+ * @param logContext 不包含业务参数和值的日志上下文
27
+ * @returns 解析后的缓存 key
28
+ */
29
+ function resolveCacheKey(
30
+ keyResolver: CacheKeyResolver | undefined,
31
+ args: unknown[],
32
+ logContext: CacheLogContext
33
+ ): string {
34
+ if (keyResolver === undefined || keyResolver === null) {
35
+ return KeyBuilder.build(logContext.cacheName, args);
36
+ }
37
+ if (typeof keyResolver === 'string') {
38
+ return KeyBuilder.build(logContext.cacheName, [keyResolver]);
39
+ }
40
+ try {
41
+ return KeyBuilder.build(logContext.cacheName, [keyResolver(...args)]);
42
+ } catch (_error) {
43
+ logCacheEvent('cache.key_fallback', { ...logContext, reason: 'resolver_error' });
44
+ return KeyBuilder.build(logContext.cacheName, args);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 获取淘汰操作使用的 Provider,并在解析失败时记录原始注册表错误。
50
+ * @param providerName decorator 配置中的 Provider 名称。
51
+ * @param logContext 当前方法的稳定日志上下文。
52
+ * @returns 已注册的缓存 Provider。
53
+ * @throws Provider 注册表抛出的原始错误。
54
+ */
55
+ function resolveCacheProvider(providerName: string | undefined, logContext: CacheLogContext): CacheProvider {
56
+ try {
57
+ return CacheProviderRegistry.get(providerName);
58
+ } catch (error) {
59
+ logCacheEvent('cache.operation_failed', { ...logContext, operation: 'provider_resolution', error });
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * 保持 fire-and-forget 语义发起单 key 删除,只处理调用当下可观察的同步失败。
66
+ * @param provider 当前淘汰使用的 Provider。
67
+ * @param cacheKey 待删除的完整 key;不会进入日志元数据。
68
+ * @param logContext 当前方法的稳定日志上下文。
69
+ * @returns 无返回值;异步删除 Promise 不会被等待或消费。
70
+ * @throws Provider delete 同步抛出的原始错误。
71
+ */
72
+ function dispatchCacheDelete(provider: CacheProvider, cacheKey: string, logContext: CacheLogContext): void {
73
+ try {
74
+ provider.delete(cacheKey);
75
+ } catch (error) {
76
+ logCacheEvent('cache.operation_failed', { ...logContext, operation: 'evict', error });
77
+ throw error;
78
+ }
79
+ logCacheEvent('cache.evict_dispatched', { ...logContext, scope: 'key' });
80
+ }
81
+
82
+ /**
83
+ * 缓存清除装饰器
84
+ * 在方法执行后清除对应的缓存条目
85
+ * @param cacheName 缓存名称
86
+ * @param options 配置项
87
+ */
88
+ export function CacheEvict(
89
+ cacheName: string,
90
+ options?: CacheEvictOptions
91
+ ): (_target: object, _propertyKey: string, descriptor: PropertyDescriptor) => void {
92
+ return function (_target: object, propertyKey: string, descriptor: PropertyDescriptor) {
93
+ const originalMethod = descriptor.value;
94
+ const logContext: CacheLogContext = {
95
+ cacheName,
96
+ methodName: propertyKey,
97
+ providerName: cacheProviderLabel(options?.providerName),
98
+ };
99
+
100
+ descriptor.value = async function (...args: unknown[]) {
101
+ let result: unknown;
102
+ try {
103
+ result = await originalMethod.apply(this, args);
104
+ } catch (error) {
105
+ logCacheEvent('cache.evict_skipped', { ...logContext, reason: 'business_error' });
106
+ throw error;
107
+ }
108
+
109
+ const provider = resolveCacheProvider(options?.providerName, logContext);
110
+
111
+ if (options?.allEntries) {
112
+ try {
113
+ await provider.deleteByPattern(cacheName + '*');
114
+ } catch (error) {
115
+ logCacheEvent('cache.operation_failed', { ...logContext, operation: 'evict', error });
116
+ throw error;
117
+ }
118
+ logCacheEvent('cache.evict_completed', { ...logContext, scope: 'allEntries' });
119
+ } else {
120
+ const cacheKey = resolveCacheKey(options?.key, args, logContext);
121
+ dispatchCacheDelete(provider, cacheKey, logContext);
122
+ }
123
+
124
+ return result;
125
+ };
126
+ };
127
+ }
128
+
129
+ export { CacheProviderRegistry } from '../core/cache-provider-registry';