@jintianxiayu/cache-decorator 0.1.2 → 0.1.3

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.
@@ -15,37 +15,37 @@ export type CacheKeyResolver = null | string | ((...args: unknown[]) => string);
15
15
  * @Cache 装饰器配置项
16
16
  */
17
17
  export interface CacheOptions {
18
- /**
19
- * 过期时间(秒)
20
- */
21
- ttl?: number;
22
-
23
- /**
24
- * 指定 CacheProvider 名称
25
- */
26
- providerName?: string;
27
-
28
- /**
29
- * 自定义缓存 key 生成逻辑
30
- * - undefined/null: 使用默认逻辑 KeyBuilder.build(cacheName, args)
31
- * - string: 使用 KeyBuilder.build(cacheName, [key])
32
- * - function: 调用函数后使用 KeyBuilder.build(cacheName, [result])
33
- */
34
- key?: CacheKeyResolver;
18
+ /**
19
+ * 过期时间(秒)
20
+ */
21
+ ttl?: number;
22
+
23
+ /**
24
+ * 指定 CacheProvider 名称
25
+ */
26
+ providerName?: string;
27
+
28
+ /**
29
+ * 自定义缓存 key 生成逻辑
30
+ * - undefined/null: 使用默认逻辑 KeyBuilder.build(cacheName, args)
31
+ * - string: 使用 KeyBuilder.build(cacheName, [key])
32
+ * - function: 调用函数后使用 KeyBuilder.build(cacheName, [result])
33
+ */
34
+ key?: CacheKeyResolver;
35
35
  }
36
36
 
37
37
  /**
38
38
  * 成功缓存条目
39
39
  */
40
40
  interface SuccessCacheEntry<T> {
41
- value: T;
41
+ value: T;
42
42
  }
43
43
 
44
44
  /**
45
45
  * 错误缓存条目
46
46
  */
47
47
  interface ErrorCacheEntry {
48
- error: unknown;
48
+ error: unknown;
49
49
  }
50
50
 
51
51
  /**
@@ -63,17 +63,17 @@ const pendingCache = new PendingCache();
63
63
  * @returns 解析后的缓存 key
64
64
  */
65
65
  function resolveCacheKey(cacheName: string, keyResolver: CacheKeyResolver | undefined, args: unknown[]): string {
66
- if (keyResolver === undefined || keyResolver === null) {
67
- return KeyBuilder.build(cacheName, args);
68
- }
69
- if (typeof keyResolver === 'string') {
70
- return KeyBuilder.build(cacheName, [keyResolver]);
71
- }
72
- try {
73
- return KeyBuilder.build(cacheName, [keyResolver(...args)]);
74
- } catch {
75
- return KeyBuilder.build(cacheName, args);
76
- }
66
+ if (keyResolver === undefined || keyResolver === null) {
67
+ return KeyBuilder.build(cacheName, args);
68
+ }
69
+ if (typeof keyResolver === 'string') {
70
+ return KeyBuilder.build(cacheName, [keyResolver]);
71
+ }
72
+ try {
73
+ return KeyBuilder.build(cacheName, [keyResolver(...args)]);
74
+ } catch {
75
+ return KeyBuilder.build(cacheName, args);
76
+ }
77
77
  }
78
78
 
79
79
  /**
@@ -83,47 +83,43 @@ function resolveCacheKey(cacheName: string, keyResolver: CacheKeyResolver | unde
83
83
  * @param options 配置项
84
84
  */
85
85
  export function Cache(cacheName: string, options?: CacheOptions) {
86
- return function <T>(
87
- _target: object,
88
- _propertyKey: string,
89
- descriptor: PropertyDescriptor,
90
- ) {
91
- const originalMethod = descriptor.value;
92
-
93
- descriptor.value = async function (...args: unknown[]) {
94
- const cacheKey = resolveCacheKey(cacheName, options?.key, args);
95
- const providerName = options?.providerName;
96
- const provider = CacheProviderRegistry.get(providerName);
97
-
98
- const cached = await provider.get(cacheKey);
99
- if (cached !== undefined) {
100
- const entry = cached as CacheEntry<T>;
101
- if ('error' in entry) {
102
- throw entry.error;
103
- }
104
- return entry.value;
105
- }
106
-
107
- const pending = pendingCache.get<T>(cacheKey);
108
- if (pending) {
109
- return pending;
110
- }
111
-
112
- const promise = (async () => {
113
- try {
114
- const result = await originalMethod.apply(this, args);
115
- provider.set(cacheKey, { value: result } as CacheEntry<T>, options?.ttl);
116
- return result;
117
- } catch (error) {
118
- provider.set(cacheKey, { error } as CacheEntry<T>, options?.ttl);
119
- throw error;
120
- }
121
- })();
122
-
123
- pendingCache.set(cacheKey, promise);
124
- return promise;
86
+ return function <T>(_target: object, _propertyKey: string, descriptor: PropertyDescriptor) {
87
+ const originalMethod = descriptor.value;
88
+
89
+ descriptor.value = async function (...args: unknown[]) {
90
+ const cacheKey = resolveCacheKey(cacheName, options?.key, args);
91
+ const providerName = options?.providerName;
92
+ const provider = CacheProviderRegistry.get(providerName);
93
+
94
+ const cached = await provider.get(cacheKey);
95
+ if (cached !== undefined) {
96
+ const entry = cached as CacheEntry<T>;
97
+ if ('error' in entry) {
98
+ throw entry.error;
99
+ }
100
+ return entry.value;
101
+ }
102
+
103
+ const pending = pendingCache.get<T>(cacheKey);
104
+ if (pending) {
105
+ return pending;
106
+ }
107
+
108
+ const promise = (async () => {
109
+ try {
110
+ const result = await originalMethod.apply(this, args);
111
+ provider.set(cacheKey, { value: result } as CacheEntry<T>, options?.ttl);
112
+ return result;
113
+ } catch (error) {
114
+ provider.set(cacheKey, { error } as CacheEntry<T>, options?.ttl);
115
+ throw error;
116
+ }
117
+ })();
118
+
119
+ pendingCache.set(cacheKey, promise);
120
+ return promise;
121
+ };
125
122
  };
126
- };
127
123
  }
128
124
 
129
- export { CacheProviderRegistry } from '../core/cache-provider-registry';
125
+ export { CacheProviderRegistry } from '../core/cache-provider-registry';
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  export * from './core/cache-provider';
3
2
  export * from './core/cache-provider-registry';
4
3
  export * from './core/key-builder';
@@ -4,175 +4,175 @@ import { CacheProviderRegistry } from '../src/core/cache-provider-registry';
4
4
  import { MemoryCacheProvider } from '../src/core/native-cache';
5
5
 
6
6
  describe('@CacheEvict 装饰器', () => {
7
- let memoryProvider: MemoryCacheProvider;
8
-
9
- beforeAll(() => {
10
- memoryProvider = new MemoryCacheProvider();
11
- CacheProviderRegistry.register('memory', memoryProvider);
12
- CacheProviderRegistry.setDefault('memory');
13
- });
14
-
15
- afterEach(() => {
16
- memoryProvider.clear();
17
- });
18
-
19
- describe('按入参清除', () => {
20
- it('应清除对应缓存条目', async () => {
21
- let getUserCallCount = 0;
22
- let updateUserCallCount = 0;
23
-
24
- class UserService {
25
- @Cache('user-cache')
26
- async getUser(id: number) {
27
- getUserCallCount++;
28
- return { id };
29
- }
30
-
31
- @CacheEvict('user-cache')
32
- async updateUser(id: number) {
33
- updateUserCallCount++;
34
- return { id, updated: true };
35
- }
36
- }
37
-
38
- const service = new UserService();
39
- await service.getUser(1);
40
- await service.getUser(1);
41
- expect(getUserCallCount).toBe(1);
42
-
43
- await service.updateUser(1);
44
- await service.getUser(1);
45
- expect(getUserCallCount).toBe(2);
46
- expect(updateUserCallCount).toBe(1);
7
+ let memoryProvider: MemoryCacheProvider;
8
+
9
+ beforeAll(() => {
10
+ memoryProvider = new MemoryCacheProvider();
11
+ CacheProviderRegistry.register('memory', memoryProvider);
12
+ CacheProviderRegistry.setDefault('memory');
47
13
  });
48
- });
49
-
50
- describe('清除所有条目', () => {
51
- it('应清除该缓存名称下所有条目', async () => {
52
- let getUserCallCount = 0;
53
- let getOrderCallCount = 0;
54
- let clearCallCount = 0;
55
-
56
- class Service {
57
- @Cache('user-cache')
58
- async getUser(id: number) {
59
- getUserCallCount++;
60
- return { id };
61
- }
62
-
63
- @Cache('order-cache')
64
- async getOrder(id: number) {
65
- getOrderCallCount++;
66
- return { id };
67
- }
68
-
69
- @CacheEvict('user-cache', { allEntries: true })
70
- async clearAllUsers() {
71
- clearCallCount++;
72
- return true;
73
- }
74
- }
75
-
76
- const service = new Service();
77
- await service.getUser(1);
78
- await service.getUser(2);
79
- await service.getOrder(1);
80
- expect(getUserCallCount).toBe(2);
81
- expect(getOrderCallCount).toBe(1);
82
-
83
- await service.clearAllUsers();
84
- expect(clearCallCount).toBe(1);
85
-
86
- await service.getUser(1);
87
- await service.getUser(2);
88
- await service.getOrder(1);
89
- expect(getUserCallCount).toBe(4);
90
- expect(getOrderCallCount).toBe(1);
14
+
15
+ afterEach(() => {
16
+ memoryProvider.clear();
91
17
  });
92
- });
93
-
94
- describe('key 选项', () => {
95
- it('key 为字符串时应删除对应缓存条目', async () => {
96
- let getUserCallCount = 0;
97
-
98
- class UserService {
99
- @Cache('user-cache', { key: 'all-users' })
100
- async getUsers() {
101
- getUserCallCount++;
102
- return [{ id: 1 }, { id: 2 }];
103
- }
104
-
105
- @CacheEvict('user-cache', { key: 'all-users' })
106
- async clearUsers() {
107
- return true;
108
- }
109
- }
110
-
111
- const service = new UserService();
112
- await service.getUsers();
113
- await service.getUsers();
114
- expect(getUserCallCount).toBe(1);
115
-
116
- await service.clearUsers();
117
- await service.getUsers();
118
- expect(getUserCallCount).toBe(2);
18
+
19
+ describe('按入参清除', () => {
20
+ it('应清除对应缓存条目', async () => {
21
+ let getUserCallCount = 0;
22
+ let updateUserCallCount = 0;
23
+
24
+ class UserService {
25
+ @Cache('user-cache')
26
+ async getUser(id: number) {
27
+ getUserCallCount++;
28
+ return { id };
29
+ }
30
+
31
+ @CacheEvict('user-cache')
32
+ async updateUser(id: number) {
33
+ updateUserCallCount++;
34
+ return { id, updated: true };
35
+ }
36
+ }
37
+
38
+ const service = new UserService();
39
+ await service.getUser(1);
40
+ await service.getUser(1);
41
+ expect(getUserCallCount).toBe(1);
42
+
43
+ await service.updateUser(1);
44
+ await service.getUser(1);
45
+ expect(getUserCallCount).toBe(2);
46
+ expect(updateUserCallCount).toBe(1);
47
+ });
119
48
  });
120
49
 
121
- it('key 为函数时应使用函数返回值删除缓存条目', async () => {
122
- let getUserCallCount = 0;
123
-
124
- class UserService {
125
- @Cache('user-cache', { key: (...args: unknown[]) => String(args[0]) })
126
- async getUser(id: number) {
127
- getUserCallCount++;
128
- return { id };
129
- }
130
-
131
- @CacheEvict('user-cache', { key: (...args: unknown[]) => String(args[0]) })
132
- async deleteUser(id: number) {
133
- return { id, deleted: true };
134
- }
135
- }
136
-
137
- const service = new UserService();
138
- await service.getUser(1);
139
- await service.getUser(2);
140
- expect(getUserCallCount).toBe(2);
141
-
142
- await service.deleteUser(1);
143
- await service.getUser(1);
144
- await service.getUser(2);
145
- expect(getUserCallCount).toBe(3);
50
+ describe('清除所有条目', () => {
51
+ it('应清除该缓存名称下所有条目', async () => {
52
+ let getUserCallCount = 0;
53
+ let getOrderCallCount = 0;
54
+ let clearCallCount = 0;
55
+
56
+ class Service {
57
+ @Cache('user-cache')
58
+ async getUser(id: number) {
59
+ getUserCallCount++;
60
+ return { id };
61
+ }
62
+
63
+ @Cache('order-cache')
64
+ async getOrder(id: number) {
65
+ getOrderCallCount++;
66
+ return { id };
67
+ }
68
+
69
+ @CacheEvict('user-cache', { allEntries: true })
70
+ async clearAllUsers() {
71
+ clearCallCount++;
72
+ return true;
73
+ }
74
+ }
75
+
76
+ const service = new Service();
77
+ await service.getUser(1);
78
+ await service.getUser(2);
79
+ await service.getOrder(1);
80
+ expect(getUserCallCount).toBe(2);
81
+ expect(getOrderCallCount).toBe(1);
82
+
83
+ await service.clearAllUsers();
84
+ expect(clearCallCount).toBe(1);
85
+
86
+ await service.getUser(1);
87
+ await service.getUser(2);
88
+ await service.getOrder(1);
89
+ expect(getUserCallCount).toBe(4);
90
+ expect(getOrderCallCount).toBe(1);
91
+ });
146
92
  });
147
93
 
148
- it('allEntries 为 true 时忽略 key 选项', async () => {
149
- let getUserCallCount = 0;
150
- let clearCallCount = 0;
151
-
152
- class UserService {
153
- @Cache('user-cache', { key: 'specific-key' })
154
- async getUsers() {
155
- getUserCallCount++;
156
- return [];
157
- }
158
-
159
- @CacheEvict('user-cache', { allEntries: true, key: 'ignored-key' })
160
- async clearAllUsers() {
161
- clearCallCount++;
162
- return true;
163
- }
164
- }
165
-
166
- const service = new UserService();
167
- await service.getUsers();
168
- await service.getUsers();
169
- expect(getUserCallCount).toBe(1);
170
-
171
- await service.clearAllUsers();
172
- expect(clearCallCount).toBe(1);
173
-
174
- await service.getUsers();
175
- expect(getUserCallCount).toBe(2);
94
+ describe('key 选项', () => {
95
+ it('key 为字符串时应删除对应缓存条目', async () => {
96
+ let getUserCallCount = 0;
97
+
98
+ class UserService {
99
+ @Cache('user-cache', { key: 'all-users' })
100
+ async getUsers() {
101
+ getUserCallCount++;
102
+ return [{ id: 1 }, { id: 2 }];
103
+ }
104
+
105
+ @CacheEvict('user-cache', { key: 'all-users' })
106
+ async clearUsers() {
107
+ return true;
108
+ }
109
+ }
110
+
111
+ const service = new UserService();
112
+ await service.getUsers();
113
+ await service.getUsers();
114
+ expect(getUserCallCount).toBe(1);
115
+
116
+ await service.clearUsers();
117
+ await service.getUsers();
118
+ expect(getUserCallCount).toBe(2);
119
+ });
120
+
121
+ it('key 为函数时应使用函数返回值删除缓存条目', async () => {
122
+ let getUserCallCount = 0;
123
+
124
+ class UserService {
125
+ @Cache('user-cache', { key: (...args: unknown[]) => String(args[0]) })
126
+ async getUser(id: number) {
127
+ getUserCallCount++;
128
+ return { id };
129
+ }
130
+
131
+ @CacheEvict('user-cache', { key: (...args: unknown[]) => String(args[0]) })
132
+ async deleteUser(id: number) {
133
+ return { id, deleted: true };
134
+ }
135
+ }
136
+
137
+ const service = new UserService();
138
+ await service.getUser(1);
139
+ await service.getUser(2);
140
+ expect(getUserCallCount).toBe(2);
141
+
142
+ await service.deleteUser(1);
143
+ await service.getUser(1);
144
+ await service.getUser(2);
145
+ expect(getUserCallCount).toBe(3);
146
+ });
147
+
148
+ it('allEntries 为 true 时忽略 key 选项', async () => {
149
+ let getUserCallCount = 0;
150
+ let clearCallCount = 0;
151
+
152
+ class UserService {
153
+ @Cache('user-cache', { key: 'specific-key' })
154
+ async getUsers() {
155
+ getUserCallCount++;
156
+ return [];
157
+ }
158
+
159
+ @CacheEvict('user-cache', { allEntries: true, key: 'ignored-key' })
160
+ async clearAllUsers() {
161
+ clearCallCount++;
162
+ return true;
163
+ }
164
+ }
165
+
166
+ const service = new UserService();
167
+ await service.getUsers();
168
+ await service.getUsers();
169
+ expect(getUserCallCount).toBe(1);
170
+
171
+ await service.clearAllUsers();
172
+ expect(clearCallCount).toBe(1);
173
+
174
+ await service.getUsers();
175
+ expect(getUserCallCount).toBe(2);
176
+ });
176
177
  });
177
- });
178
- });
178
+ });
@@ -2,35 +2,35 @@ import { CacheProviderRegistry } from '../src/core/cache-provider-registry';
2
2
  import { MemoryCacheProvider } from '../src/core/native-cache';
3
3
 
4
4
  describe('CacheProviderRegistry', () => {
5
- let memoryProvider: MemoryCacheProvider;
5
+ let memoryProvider: MemoryCacheProvider;
6
6
 
7
- beforeEach(() => {
8
- memoryProvider = new MemoryCacheProvider();
9
- CacheProviderRegistry.register('memory', memoryProvider);
10
- });
11
-
12
- afterEach(() => {
13
- CacheProviderRegistry.clear();
14
- });
15
-
16
- describe('register & get', () => {
17
- it('应注册并获取 Provider', () => {
18
- expect(CacheProviderRegistry.get('memory')).toBe(memoryProvider);
7
+ beforeEach(() => {
8
+ memoryProvider = new MemoryCacheProvider();
9
+ CacheProviderRegistry.register('memory', memoryProvider);
19
10
  });
20
11
 
21
- it('应在 Provider 不存在时抛出错误', () => {
22
- expect(() => CacheProviderRegistry.get('nonexistent')).toThrow();
12
+ afterEach(() => {
13
+ CacheProviderRegistry.clear();
23
14
  });
24
- });
25
15
 
26
- describe('setDefault & get', () => {
27
- it('应设置并获取默认 Provider', () => {
28
- CacheProviderRegistry.setDefault('memory');
29
- expect(CacheProviderRegistry.get()).toBe(memoryProvider);
16
+ describe('register & get', () => {
17
+ it('应注册并获取 Provider', () => {
18
+ expect(CacheProviderRegistry.get('memory')).toBe(memoryProvider);
19
+ });
20
+
21
+ it('应在 Provider 不存在时抛出错误', () => {
22
+ expect(() => CacheProviderRegistry.get('nonexistent')).toThrow();
23
+ });
30
24
  });
31
25
 
32
- it('应在未设置默认且未指定时抛出错误', () => {
33
- expect(() => CacheProviderRegistry.get()).toThrow();
26
+ describe('setDefault & get', () => {
27
+ it('应设置并获取默认 Provider', () => {
28
+ CacheProviderRegistry.setDefault('memory');
29
+ expect(CacheProviderRegistry.get()).toBe(memoryProvider);
30
+ });
31
+
32
+ it('应在未设置默认且未指定时抛出错误', () => {
33
+ expect(() => CacheProviderRegistry.get()).toThrow();
34
+ });
34
35
  });
35
- });
36
- });
36
+ });