koatty_cacheable 1.4.2 → 1.5.0

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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [1.5.0](https://github.com/thinkkoa/koatty_cacheable/compare/v1.4.3...v1.5.0) (2024-04-01)
6
+
7
+
8
+ ### Features
9
+
10
+ * delayedDoubleDeletion ([532f735](https://github.com/thinkkoa/koatty_cacheable/commit/532f735818fc66fa144023cd24282efe350833ba))
11
+
12
+ ### [1.4.3](https://github.com/thinkkoa/koatty_cacheable/compare/v1.4.2...v1.4.3) (2024-01-17)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * 缓存key拼装 ([5d0b924](https://github.com/thinkkoa/koatty_cacheable/commit/5d0b9248064d353046bd7287d3a3ee5229e88c23))
18
+
5
19
  ### [1.4.2](https://github.com/thinkkoa/koatty_cacheable/compare/v1.4.1...v1.4.2) (2023-12-20)
6
20
 
7
21
  ### [1.4.1](https://github.com/thinkkoa/koatty_cacheable/compare/v1.4.0...v1.4.1) (2023-08-04)
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2023-12-20 19:24:59
3
+ * @Date: 2024-04-01 15:47:51
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -9,9 +9,11 @@ import { Application } from 'koatty_container';
9
9
  import { CacheStore } from 'koatty_store';
10
10
 
11
11
  /**
12
- * Decorate this method to support caching. Redis server config from db.ts.
13
- * The cache method returns a value to ensure that the next time the method is executed with the same parameters,
14
- * the results can be obtained directly from the cache without the need to execute the method again.
12
+ * Decorate this method to support caching.
13
+ * The cache method returns a value to ensure that the next time
14
+ * the method is executed with the same parameters, the results can be obtained
15
+ * directly from the cache without the need to execute the method again.
16
+ * CacheStore server config defined in db.ts.
15
17
  *
16
18
  * @export
17
19
  * @param {string} cacheName cache name
@@ -36,7 +38,8 @@ export declare interface CacheAbleOpt {
36
38
  }
37
39
 
38
40
  /**
39
- * Decorating the execution of this method will trigger a cache clear operation. Redis server config from db.ts.
41
+ * Decorating the execution of this method will trigger a cache clear operation.
42
+ * CacheStore server config defined in db.ts.
40
43
  *
41
44
  * @export
42
45
  * @param {string} cacheName cacheName cache name
@@ -44,9 +47,10 @@ export declare interface CacheAbleOpt {
44
47
  * e.g:
45
48
  * {
46
49
  * params: ["id"],
47
- * eventTime: "Before"
50
+ * delayedDoubleDeletion: true
48
51
  * }
49
- * Use the 'id' parameters of the method as cache subkeys, and clear the cache before the method executed
52
+ * Use the 'id' parameters of the method as cache subkeys,
53
+ * and clear the cache after the method executed
50
54
  * @returns
51
55
  */
52
56
  export declare function CacheEvict(cacheName: string, opt?: CacheEvictOpt): (target: any, methodName: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -57,14 +61,9 @@ export declare function CacheEvict(cacheName: string, opt?: CacheEvictOpt): (tar
57
61
  */
58
62
  export declare interface CacheEvictOpt {
59
63
  params?: string[];
60
- eventTime?: "Before";
64
+ delayedDoubleDeletion?: boolean;
61
65
  }
62
66
 
63
- /**
64
- *
65
- */
66
- export declare type eventTimes = "Before" | "After";
67
-
68
67
  /**
69
68
  * get instances of storeCache
70
69
  *
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2023-12-20 19:24:38
3
+ * @Date: 2024-04-01 15:47:40
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -15,11 +15,11 @@ var koatty_container = require('koatty_container');
15
15
  /*
16
16
  * @Author: richen
17
17
  * @Date: 2020-07-06 19:53:43
18
- * @LastEditTime: 2023-08-04 14:33:58
18
+ * @LastEditTime: 2024-04-01 15:44:15
19
19
  * @Description:
20
20
  * @Copyright (c) - <richenlin(at)gmail.com>
21
21
  */
22
- const PreKey = "k";
22
+ const longKey = 128;
23
23
  // storeCache
24
24
  const storeCache = {
25
25
  store: null
@@ -61,9 +61,11 @@ async function InitCacheStore() {
61
61
  });
62
62
  }
63
63
  /**
64
- * Decorate this method to support caching. Redis server config from db.ts.
65
- * The cache method returns a value to ensure that the next time the method is executed with the same parameters,
66
- * the results can be obtained directly from the cache without the need to execute the method again.
64
+ * Decorate this method to support caching.
65
+ * The cache method returns a value to ensure that the next time
66
+ * the method is executed with the same parameters, the results can be obtained
67
+ * directly from the cache without the need to execute the method again.
68
+ * CacheStore server config defined in db.ts.
67
69
  *
68
70
  * @export
69
71
  * @param {string} cacheName cache name
@@ -78,7 +80,7 @@ async function InitCacheStore() {
78
80
  */
79
81
  function CacheAble(cacheName, opt = {
80
82
  params: [],
81
- timeout: 3600,
83
+ timeout: 300,
82
84
  }) {
83
85
  return (target, methodName, descriptor) => {
84
86
  const componentType = koatty_container.IOCContainer.getType(target);
@@ -89,11 +91,11 @@ function CacheAble(cacheName, opt = {
89
91
  opt = {
90
92
  ...{
91
93
  params: [],
92
- timeout: 3600,
94
+ timeout: 300,
93
95
  }, ...opt
94
96
  };
95
97
  // 获取定义的参数位置
96
- const paramIndexes = getParamIndex(opt.params, getArgs(value));
98
+ const paramIndexes = getParamIndex(opt.params);
97
99
  descriptor = {
98
100
  configurable,
99
101
  enumerable,
@@ -107,35 +109,31 @@ function CacheAble(cacheName, opt = {
107
109
  });
108
110
  if (cacheFlag) {
109
111
  // tslint:disable-next-line: one-variable-per-declaration
110
- let key = PreKey;
112
+ let key = cacheName;
111
113
  if (props && props.length > 0) {
112
114
  for (const item of paramIndexes) {
113
115
  if (props[item] !== undefined) {
114
116
  const value = koatty_lib.Helper.toString(props[item]);
115
- key += `:${value}`;
117
+ key += `:${opt.params[item]}:${value}`;
116
118
  }
117
119
  }
118
120
  // 防止key超长
119
- if (key.length > 32) {
121
+ if (key.length > longKey) {
120
122
  key = koatty_lib.Helper.murmurHash(key);
121
123
  }
122
124
  }
123
- let res = await store.get(`${cacheName}:${key}`).catch(() => null);
125
+ let res = await store.get(key).catch(() => null);
124
126
  if (!koatty_lib.Helper.isEmpty(res)) {
125
127
  return JSON.parse(res);
126
128
  }
127
129
  // tslint:disable-next-line: no-invalid-this
128
130
  res = await value.apply(this, props);
129
131
  // prevent cache penetration
130
- if (koatty_lib.Helper.isEmpty(res)) {
132
+ if (koatty_lib.Helper.isTrueEmpty(res)) {
131
133
  res = "";
132
- opt.timeout = 5;
133
- }
134
- if (!opt.timeout) {
135
- opt.timeout = 3600;
136
134
  }
137
135
  // async set store
138
- store.set(`${cacheName}:${key}`, JSON.stringify(res), opt.timeout).catch(() => null);
136
+ store.set(key, JSON.stringify(res), opt.timeout).catch(() => null);
139
137
  return res;
140
138
  }
141
139
  else {
@@ -150,7 +148,8 @@ function CacheAble(cacheName, opt = {
150
148
  };
151
149
  }
152
150
  /**
153
- * Decorating the execution of this method will trigger a cache clear operation. Redis server config from db.ts.
151
+ * Decorating the execution of this method will trigger a cache clear operation.
152
+ * CacheStore server config defined in db.ts.
154
153
  *
155
154
  * @export
156
155
  * @param {string} cacheName cacheName cache name
@@ -158,13 +157,14 @@ function CacheAble(cacheName, opt = {
158
157
  * e.g:
159
158
  * {
160
159
  * params: ["id"],
161
- * eventTime: "Before"
160
+ * delayedDoubleDeletion: true
162
161
  * }
163
- * Use the 'id' parameters of the method as cache subkeys, and clear the cache before the method executed
162
+ * Use the 'id' parameters of the method as cache subkeys,
163
+ * and clear the cache after the method executed
164
164
  * @returns
165
165
  */
166
166
  function CacheEvict(cacheName, opt = {
167
- eventTime: "Before",
167
+ delayedDoubleDeletion: true,
168
168
  }) {
169
169
  return (target, methodName, descriptor) => {
170
170
  const componentType = koatty_container.IOCContainer.getType(target);
@@ -178,7 +178,7 @@ function CacheEvict(cacheName, opt = {
178
178
  eventTime: "Before",
179
179
  }, ...opt
180
180
  };
181
- const paramIndexes = getParamIndex(opt.params, getArgs(value));
181
+ const paramIndexes = getParamIndex(opt.params);
182
182
  descriptor = {
183
183
  configurable,
184
184
  enumerable,
@@ -191,30 +191,28 @@ function CacheEvict(cacheName, opt = {
191
191
  return null;
192
192
  });
193
193
  if (cacheFlag) {
194
- let key = PreKey;
194
+ let key = cacheName;
195
195
  if (props && props.length > 0) {
196
196
  for (const item of paramIndexes) {
197
197
  if (props[item] !== undefined) {
198
198
  const value = koatty_lib.Helper.toString(props[item]);
199
- key += `:${value}`;
199
+ key += `:${opt.params[item]}:${value}`;
200
200
  }
201
201
  }
202
202
  // 防止key超长
203
- if (key.length > 32) {
203
+ if (key.length > longKey) {
204
204
  key = koatty_lib.Helper.murmurHash(key);
205
205
  }
206
206
  }
207
- if (opt.eventTime === "Before") {
208
- await store.del(`${cacheName}:${key}`).catch(() => null);
209
- // tslint:disable-next-line: no-invalid-this
210
- return value.apply(this, props);
211
- }
212
- else {
213
- // tslint:disable-next-line: no-invalid-this
214
- const res = await value.apply(this, props);
215
- store.del(`${cacheName}:${key}`).catch(() => null);
216
- return res;
207
+ // tslint:disable-next-line: no-invalid-this
208
+ const res = await value.apply(this, props);
209
+ store.del(key).catch(() => null);
210
+ if (opt.delayedDoubleDeletion) {
211
+ asyncDelayedExecution(2000, () => {
212
+ store.del(key).catch(() => null);
213
+ });
217
214
  }
215
+ return res;
218
216
  }
219
217
  else {
220
218
  // tslint:disable-next-line: no-invalid-this
@@ -229,31 +227,10 @@ function CacheEvict(cacheName, opt = {
229
227
  }
230
228
  /**
231
229
  * @description:
232
- * @param {*} func
233
- * @return {*}
234
- */
235
- function getArgs(func) {
236
- // 首先匹配函数括弧里的参数
237
- const args = func.toString().match(/.*?\(([^)]*)\)/);
238
- if (args.length > 1) {
239
- // 分解参数成数组
240
- return args[1].split(",").map(function (a) {
241
- // 去空格和内联注释
242
- return a.replace(/\/\*.*\*\//, "").trim();
243
- }).filter(function (ae) {
244
- // 确保没有undefineds
245
- return ae;
246
- });
247
- }
248
- return [];
249
- }
250
- /**
251
- * @description:
252
- * @param {string} params
253
- * @param {string} args
230
+ * @param {string[]} params
254
231
  * @return {*}
255
232
  */
256
- function getParamIndex(params, args) {
233
+ function getParamIndex(params) {
257
234
  const res = [];
258
235
  for (let i = 0; i < params.length; i++) {
259
236
  if (params.includes(params[i])) {
@@ -261,6 +238,24 @@ function getParamIndex(params, args) {
261
238
  }
262
239
  }
263
240
  return res;
241
+ }
242
+ /**
243
+ *
244
+ * @param ms
245
+ * @returns
246
+ */
247
+ function delay(ms) {
248
+ return new Promise(resolve => setTimeout(resolve, ms));
249
+ }
250
+ /**
251
+ * async delayed execution func
252
+ * @param ms
253
+ * @param fn
254
+ * @returns
255
+ */
256
+ async function asyncDelayedExecution(ms, fn) {
257
+ await delay(ms); // delay ms second
258
+ return fn();
264
259
  }
265
260
 
266
261
  exports.CacheAble = CacheAble;
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2023-12-20 19:24:38
3
+ * @Date: 2024-04-01 15:47:40
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -13,11 +13,11 @@ import { IOCContainer } from 'koatty_container';
13
13
  /*
14
14
  * @Author: richen
15
15
  * @Date: 2020-07-06 19:53:43
16
- * @LastEditTime: 2023-08-04 14:33:58
16
+ * @LastEditTime: 2024-04-01 15:44:15
17
17
  * @Description:
18
18
  * @Copyright (c) - <richenlin(at)gmail.com>
19
19
  */
20
- const PreKey = "k";
20
+ const longKey = 128;
21
21
  // storeCache
22
22
  const storeCache = {
23
23
  store: null
@@ -59,9 +59,11 @@ async function InitCacheStore() {
59
59
  });
60
60
  }
61
61
  /**
62
- * Decorate this method to support caching. Redis server config from db.ts.
63
- * The cache method returns a value to ensure that the next time the method is executed with the same parameters,
64
- * the results can be obtained directly from the cache without the need to execute the method again.
62
+ * Decorate this method to support caching.
63
+ * The cache method returns a value to ensure that the next time
64
+ * the method is executed with the same parameters, the results can be obtained
65
+ * directly from the cache without the need to execute the method again.
66
+ * CacheStore server config defined in db.ts.
65
67
  *
66
68
  * @export
67
69
  * @param {string} cacheName cache name
@@ -76,7 +78,7 @@ async function InitCacheStore() {
76
78
  */
77
79
  function CacheAble(cacheName, opt = {
78
80
  params: [],
79
- timeout: 3600,
81
+ timeout: 300,
80
82
  }) {
81
83
  return (target, methodName, descriptor) => {
82
84
  const componentType = IOCContainer.getType(target);
@@ -87,11 +89,11 @@ function CacheAble(cacheName, opt = {
87
89
  opt = {
88
90
  ...{
89
91
  params: [],
90
- timeout: 3600,
92
+ timeout: 300,
91
93
  }, ...opt
92
94
  };
93
95
  // 获取定义的参数位置
94
- const paramIndexes = getParamIndex(opt.params, getArgs(value));
96
+ const paramIndexes = getParamIndex(opt.params);
95
97
  descriptor = {
96
98
  configurable,
97
99
  enumerable,
@@ -105,35 +107,31 @@ function CacheAble(cacheName, opt = {
105
107
  });
106
108
  if (cacheFlag) {
107
109
  // tslint:disable-next-line: one-variable-per-declaration
108
- let key = PreKey;
110
+ let key = cacheName;
109
111
  if (props && props.length > 0) {
110
112
  for (const item of paramIndexes) {
111
113
  if (props[item] !== undefined) {
112
114
  const value = Helper.toString(props[item]);
113
- key += `:${value}`;
115
+ key += `:${opt.params[item]}:${value}`;
114
116
  }
115
117
  }
116
118
  // 防止key超长
117
- if (key.length > 32) {
119
+ if (key.length > longKey) {
118
120
  key = Helper.murmurHash(key);
119
121
  }
120
122
  }
121
- let res = await store.get(`${cacheName}:${key}`).catch(() => null);
123
+ let res = await store.get(key).catch(() => null);
122
124
  if (!Helper.isEmpty(res)) {
123
125
  return JSON.parse(res);
124
126
  }
125
127
  // tslint:disable-next-line: no-invalid-this
126
128
  res = await value.apply(this, props);
127
129
  // prevent cache penetration
128
- if (Helper.isEmpty(res)) {
130
+ if (Helper.isTrueEmpty(res)) {
129
131
  res = "";
130
- opt.timeout = 5;
131
- }
132
- if (!opt.timeout) {
133
- opt.timeout = 3600;
134
132
  }
135
133
  // async set store
136
- store.set(`${cacheName}:${key}`, JSON.stringify(res), opt.timeout).catch(() => null);
134
+ store.set(key, JSON.stringify(res), opt.timeout).catch(() => null);
137
135
  return res;
138
136
  }
139
137
  else {
@@ -148,7 +146,8 @@ function CacheAble(cacheName, opt = {
148
146
  };
149
147
  }
150
148
  /**
151
- * Decorating the execution of this method will trigger a cache clear operation. Redis server config from db.ts.
149
+ * Decorating the execution of this method will trigger a cache clear operation.
150
+ * CacheStore server config defined in db.ts.
152
151
  *
153
152
  * @export
154
153
  * @param {string} cacheName cacheName cache name
@@ -156,13 +155,14 @@ function CacheAble(cacheName, opt = {
156
155
  * e.g:
157
156
  * {
158
157
  * params: ["id"],
159
- * eventTime: "Before"
158
+ * delayedDoubleDeletion: true
160
159
  * }
161
- * Use the 'id' parameters of the method as cache subkeys, and clear the cache before the method executed
160
+ * Use the 'id' parameters of the method as cache subkeys,
161
+ * and clear the cache after the method executed
162
162
  * @returns
163
163
  */
164
164
  function CacheEvict(cacheName, opt = {
165
- eventTime: "Before",
165
+ delayedDoubleDeletion: true,
166
166
  }) {
167
167
  return (target, methodName, descriptor) => {
168
168
  const componentType = IOCContainer.getType(target);
@@ -176,7 +176,7 @@ function CacheEvict(cacheName, opt = {
176
176
  eventTime: "Before",
177
177
  }, ...opt
178
178
  };
179
- const paramIndexes = getParamIndex(opt.params, getArgs(value));
179
+ const paramIndexes = getParamIndex(opt.params);
180
180
  descriptor = {
181
181
  configurable,
182
182
  enumerable,
@@ -189,30 +189,28 @@ function CacheEvict(cacheName, opt = {
189
189
  return null;
190
190
  });
191
191
  if (cacheFlag) {
192
- let key = PreKey;
192
+ let key = cacheName;
193
193
  if (props && props.length > 0) {
194
194
  for (const item of paramIndexes) {
195
195
  if (props[item] !== undefined) {
196
196
  const value = Helper.toString(props[item]);
197
- key += `:${value}`;
197
+ key += `:${opt.params[item]}:${value}`;
198
198
  }
199
199
  }
200
200
  // 防止key超长
201
- if (key.length > 32) {
201
+ if (key.length > longKey) {
202
202
  key = Helper.murmurHash(key);
203
203
  }
204
204
  }
205
- if (opt.eventTime === "Before") {
206
- await store.del(`${cacheName}:${key}`).catch(() => null);
207
- // tslint:disable-next-line: no-invalid-this
208
- return value.apply(this, props);
209
- }
210
- else {
211
- // tslint:disable-next-line: no-invalid-this
212
- const res = await value.apply(this, props);
213
- store.del(`${cacheName}:${key}`).catch(() => null);
214
- return res;
205
+ // tslint:disable-next-line: no-invalid-this
206
+ const res = await value.apply(this, props);
207
+ store.del(key).catch(() => null);
208
+ if (opt.delayedDoubleDeletion) {
209
+ asyncDelayedExecution(2000, () => {
210
+ store.del(key).catch(() => null);
211
+ });
215
212
  }
213
+ return res;
216
214
  }
217
215
  else {
218
216
  // tslint:disable-next-line: no-invalid-this
@@ -227,31 +225,10 @@ function CacheEvict(cacheName, opt = {
227
225
  }
228
226
  /**
229
227
  * @description:
230
- * @param {*} func
231
- * @return {*}
232
- */
233
- function getArgs(func) {
234
- // 首先匹配函数括弧里的参数
235
- const args = func.toString().match(/.*?\(([^)]*)\)/);
236
- if (args.length > 1) {
237
- // 分解参数成数组
238
- return args[1].split(",").map(function (a) {
239
- // 去空格和内联注释
240
- return a.replace(/\/\*.*\*\//, "").trim();
241
- }).filter(function (ae) {
242
- // 确保没有undefineds
243
- return ae;
244
- });
245
- }
246
- return [];
247
- }
248
- /**
249
- * @description:
250
- * @param {string} params
251
- * @param {string} args
228
+ * @param {string[]} params
252
229
  * @return {*}
253
230
  */
254
- function getParamIndex(params, args) {
231
+ function getParamIndex(params) {
255
232
  const res = [];
256
233
  for (let i = 0; i < params.length; i++) {
257
234
  if (params.includes(params[i])) {
@@ -259,6 +236,24 @@ function getParamIndex(params, args) {
259
236
  }
260
237
  }
261
238
  return res;
239
+ }
240
+ /**
241
+ *
242
+ * @param ms
243
+ * @returns
244
+ */
245
+ function delay(ms) {
246
+ return new Promise(resolve => setTimeout(resolve, ms));
247
+ }
248
+ /**
249
+ * async delayed execution func
250
+ * @param ms
251
+ * @param fn
252
+ * @returns
253
+ */
254
+ async function asyncDelayedExecution(ms, fn) {
255
+ await delay(ms); // delay ms second
256
+ return fn();
262
257
  }
263
258
 
264
259
  export { CacheAble, CacheEvict, GetCacheStore };
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koatty_cacheable",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Cacheable for koatty.",
5
5
  "scripts": {
6
6
  "build": "npm run build:js && npm run build:dts && npm run build:doc && npm run build:cp",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koatty_cacheable",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Cacheable for koatty.",
5
5
  "scripts": {
6
6
  "build": "npm run build:js && npm run build:dts && npm run build:doc && npm run build:cp",