koatty_store 1.5.8 → 1.6.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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2023-01-13 12:11:39
3
+ * @Date: 2023-07-28 21:00:45
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -9,609 +9,599 @@ import { flatten, isNil, union, isUndefined } from 'lodash';
9
9
  import * as helper from 'koatty_lib';
10
10
  import { EventEmitter } from 'events';
11
11
  import { DefaultLogger } from 'koatty_logger';
12
- import IORedis from 'ioredis';
12
+ import { Cluster, Redis } from 'ioredis';
13
13
  import genericPool from 'generic-pool';
14
14
 
15
15
  /*
16
16
  * @Description:
17
17
  * @Usage:
18
18
  * @Author: richen
19
- * @Date: 2021-12-02 15:26:55
20
- * @LastEditTime: 2023-01-13 11:25:37
19
+ * @Date: 2021-12-02 11:03:20
20
+ * @LastEditTime: 2023-02-18 22:02:47
21
21
  */
22
22
  /**
23
23
  *
24
24
  *
25
- * @export
26
- * @class Store
25
+ * @enum {number}
27
26
  */
28
- class CacheStore {
27
+ var messages;
28
+ (function (messages) {
29
+ messages["ok"] = "OK";
30
+ messages["queued"] = "QUEUED";
31
+ messages["pong"] = "PONG";
32
+ messages["noint"] = "ERR value is not an integer or out of range";
33
+ messages["nofloat"] = "ERR value is not an float or out of range";
34
+ messages["nokey"] = "ERR no such key";
35
+ messages["nomultiinmulti"] = "ERR MULTI calls can not be nested";
36
+ messages["nomultiexec"] = "ERR EXEC without MULTI";
37
+ messages["nomultidiscard"] = "ERR DISCARD without MULTI";
38
+ messages["busykey"] = "ERR target key name is busy";
39
+ messages["syntax"] = "ERR syntax error";
40
+ messages["unsupported"] = "MemoryCache does not support that operation";
41
+ messages["wrongTypeOp"] = "WRONGTYPE Operation against a key holding the wrong kind of value";
42
+ messages["wrongPayload"] = "DUMP payload version or checksum are wrong";
43
+ messages["wrongArgCount"] = "ERR wrong number of arguments for '%0' command";
44
+ messages["bitopnotWrongCount"] = "ERR BITOP NOT must be called with a single source key";
45
+ messages["indexOutOfRange"] = "ERR index out of range";
46
+ messages["invalidLexRange"] = "ERR min or max not valid string range item";
47
+ messages["invalidDBIndex"] = "ERR invalid DB index";
48
+ messages["invalidDBIndexNX"] = "ERR invalid DB index, '%0' does not exist";
49
+ messages["mutuallyExclusiveNXXX"] = "ERR XX and NX options at the same time are not compatible";
50
+ })(messages || (messages = {}));
51
+ class MemoryCache extends EventEmitter {
29
52
  /**
30
- * Creates an instance of CacheStore.
31
- * @param {StoreOptions} options
32
- * @memberof CacheStore
53
+ * Creates an instance of MemoryCache.
54
+ * @param {*} options
55
+ * @memberof MemoryCache
33
56
  */
34
57
  constructor(options) {
35
- this.options = options;
36
- this.pool = null;
37
- this.client = null;
38
- }
39
- getConnection() {
40
- throw new Error("Method not implemented.");
41
- }
42
- close() {
43
- throw new Error("Method not implemented.");
44
- }
45
- release(conn) {
46
- throw new Error("Method not implemented.");
47
- }
48
- defineCommand(name, scripts) {
49
- throw new Error("Method not implemented.");
50
- }
51
- getCompare(name, value) {
52
- throw new Error("Method not implemented.");
58
+ super();
59
+ this.databases = Object.create({});
60
+ this.options = { ...{ database: "0" }, ...options };
61
+ this.currentDBIndex = 0;
62
+ this.connected = false;
63
+ this.lastSave = Date.now();
64
+ this.multiMode = false;
53
65
  }
54
66
  /**
55
- * handler for native client
56
67
  *
57
- * @param {string} name
58
- * @param {any[]} data
68
+ *
59
69
  * @returns {*}
60
- * @memberof RedisStore
61
- */
62
- async wrap(name, data) {
63
- let conn;
64
- try {
65
- conn = await this.getConnection();
66
- const res = await conn[name](...data);
67
- return res;
68
- }
69
- catch (err) {
70
- throw err;
71
- }
72
- finally {
73
- this.release(conn);
74
- }
75
- }
76
- /**
77
- * 字符串获取
78
- * @param name
79
- */
80
- get(name) {
81
- return this.wrap('get', [`${this.options.keyPrefix}${name}`]);
82
- }
83
- /**
84
- * 字符串写入
85
- * @param name
86
- * @param value
87
- * @param timeout
88
- * @returns {Promise}
70
+ * @memberof MemoryCache
89
71
  */
90
- set(name, value, timeout) {
91
- if (typeof timeout !== 'number') {
92
- timeout = this.options.timeout;
93
- }
94
- return this.wrap('set', [`${this.options.keyPrefix}${name}`, value, 'ex', timeout]);
72
+ createClient() {
73
+ this.databases[this.options.database] = Object.create({});
74
+ this.cache = this.databases[this.options.database];
75
+ this.connected = true;
76
+ // exit multi mode if we are in it
77
+ this.discard(null, true);
78
+ this.emit('connect');
79
+ this.emit('ready');
80
+ return this;
95
81
  }
96
82
  /**
97
- * 以秒为单位,返回给定 key 的剩余生存时间
98
- * @param name
83
+ *
84
+ *
99
85
  * @returns {*}
86
+ * @memberof MemoryCache
100
87
  */
101
- ttl(name) {
102
- return this.wrap('ttl', [`${this.options.keyPrefix}${name}`]);
103
- }
104
- /**
105
- * 设置key超时属性
106
- * @param name
107
- * @param timeout
108
- */
109
- expire(name, timeout) {
110
- return this.wrap('expire', [`${this.options.keyPrefix}${name}`, timeout]);
111
- }
112
- /**
113
- * 删除key
114
- * @param name
115
- */
116
- rm(name) {
117
- return this.wrap('del', [`${this.options.keyPrefix}${name}`]);
88
+ quit() {
89
+ this.connected = false;
90
+ // exit multi mode if we are in it
91
+ this.discard(null, true);
92
+ this.emit('end');
93
+ return this;
118
94
  }
119
95
  /**
120
96
  *
121
97
  *
122
- * @param {*} name
123
- * @returns
124
- */
125
- del(name) {
126
- return this.wrap('del', [`${this.options.keyPrefix}${name}`]);
127
- }
128
- /**
129
- * 判断key是否存在
130
- * @param name
131
- */
132
- exists(name) {
133
- return this.wrap('exists', [`${this.options.keyPrefix}${name}`]);
134
- }
135
- /**
136
- * 自增
137
- * @param name
138
- */
139
- incr(name) {
140
- return this.wrap('incr', [`${this.options.keyPrefix}${name}`]);
141
- }
142
- /**
143
- * 自减
144
- * @param name
145
98
  * @returns {*}
99
+ * @memberof MemoryCache
146
100
  */
147
- decr(name) {
148
- return this.wrap('decr', [`${this.options.keyPrefix}${name}`]);
101
+ end() {
102
+ return this.quit();
149
103
  }
150
104
  /**
151
- * 将 key 所储存的值增加增量
152
- * @param name
153
- * @param incr
105
+ *
106
+ *
107
+ * @param {string} message
108
+ * @param {Function} [callback]
154
109
  * @returns {*}
110
+ * @memberof MemoryCache
155
111
  */
156
- incrby(name, incr = 1) {
157
- return this.wrap('incrby', [`${this.options.keyPrefix}${name}`, incr]);
112
+ echo(message, callback) {
113
+ return this._handleCallback(callback, message);
158
114
  }
159
115
  /**
160
- * 将 key 所储存的值减去减量
161
116
  *
162
- * @param {any} name
163
- * @param {any} decr
164
- */
165
- decrby(name, decr = 1) {
166
- return this.wrap('decrby', [`${this.options.keyPrefix}${name}`, decr]);
167
- }
168
- /**
169
- * 哈希写入
170
- * @param name
171
- * @param key
172
- * @param value
173
- * @param timeout
117
+ *
118
+ * @param {string} message
119
+ * @param {Function} [callback]
120
+ * @returns {*}
121
+ * @memberof MemoryCache
174
122
  */
175
- hset(name, key, value, timeout) {
176
- const setP = [this.wrap('hset', [`${this.options.keyPrefix}${name}`, key, value])];
177
- if (typeof timeout !== 'number') {
178
- timeout = this.options.timeout;
179
- }
180
- setP.push(this.set(`${name}:${key}_ex`, 1, timeout));
181
- return Promise.all(setP);
123
+ ping(message, callback) {
124
+ message = message || messages.pong;
125
+ return this._handleCallback(callback, message);
182
126
  }
183
127
  /**
184
- * 哈希获取
185
- * @param name
186
- * @param key
128
+ *
129
+ *
130
+ * @param {string} password
131
+ * @param {Function} [callback]
187
132
  * @returns {*}
133
+ * @memberof MemoryCache
188
134
  */
189
- hget(name, key) {
190
- const setP = [this.get(`${name}:${key}_ex`)];
191
- setP.push(this.wrap('hget', [`${this.options.keyPrefix}${name}`, key]));
192
- return Promise.all(setP).then(dataArr => {
193
- if (dataArr[0] === null) {
194
- this.hdel(name, key);
195
- return null;
196
- }
197
- return dataArr[1] || null;
198
- });
135
+ auth(password, callback) {
136
+ return this._handleCallback(callback, messages.ok);
199
137
  }
200
138
  /**
201
- * 查看哈希表 hashKey 中,给定域 key 是否存在
202
- * @param name
203
- * @param key
139
+ *
140
+ *
141
+ * @param {number} dbIndex
142
+ * @param {Function} [callback]
204
143
  * @returns {*}
144
+ * @memberof MemoryCache
205
145
  */
206
- hexists(name, key) {
207
- const setP = [this.get(`${name}:${key}_ex`)];
208
- setP.push(this.wrap('hexists', [`${this.options.keyPrefix}${name}`, key]));
209
- return Promise.all(setP).then(dataArr => {
210
- if (dataArr[0] === null) {
211
- this.hdel(name, key);
212
- return 0;
213
- }
214
- return dataArr[1] || 0;
215
- });
146
+ select(dbIndex, callback) {
147
+ if (!helper.isNumber(dbIndex)) {
148
+ return this._handleCallback(callback, null, messages.invalidDBIndex);
149
+ }
150
+ if (!this.databases.hasOwnProperty(dbIndex)) {
151
+ this.databases[dbIndex] = Object.create({});
152
+ }
153
+ this.multiMode = false;
154
+ this.currentDBIndex = dbIndex;
155
+ this.cache = this.databases[dbIndex];
156
+ return this._handleCallback(callback, messages.ok);
157
+ }
158
+ // ---------------------------------------
159
+ // Keys
160
+ // ---------------------------------------
161
+ get(key, callback) {
162
+ let retVal = null;
163
+ if (this._hasKey(key)) {
164
+ this._testType(key, 'string', true, callback);
165
+ retVal = this._getKey(key);
166
+ }
167
+ return this._handleCallback(callback, retVal);
216
168
  }
217
169
  /**
218
- * 哈希删除
219
- * @param name
220
- * @param key
170
+ * set(key, value, ttl, pttl, notexist, onlyexist, callback)
171
+ *
172
+ * @param {string} key
173
+ * @param {(string | number)} value
174
+ * @param {...any[]} params
221
175
  * @returns {*}
176
+ * @memberof MemoryCache
222
177
  */
223
- hdel(name, key) {
224
- const setP = [this.del(`${name}:${key}_ex`)];
225
- setP.push(this.wrap('hdel', [`${this.options.keyPrefix}${name}`, key]));
226
- return Promise.all(setP);
178
+ set(key, value, ...params) {
179
+ const retVal = null;
180
+ params = flatten(params);
181
+ const callback = this._retrieveCallback(params);
182
+ let ttl, pttl, notexist, onlyexist;
183
+ // parse parameters
184
+ while (params.length > 0) {
185
+ const param = params.shift();
186
+ switch (param.toString().toLowerCase()) {
187
+ case 'nx':
188
+ notexist = true;
189
+ break;
190
+ case 'xx':
191
+ onlyexist = true;
192
+ break;
193
+ case 'ex':
194
+ if (params.length === 0) {
195
+ return this._handleCallback(callback, null, messages.syntax);
196
+ }
197
+ ttl = parseInt(params.shift());
198
+ if (isNaN(ttl)) {
199
+ return this._handleCallback(callback, null, messages.noint);
200
+ }
201
+ break;
202
+ case 'px':
203
+ if (params.length === 0) {
204
+ return this._handleCallback(callback, null, messages.syntax);
205
+ }
206
+ pttl = parseInt(params.shift());
207
+ if (isNaN(pttl)) {
208
+ return this._handleCallback(callback, null, messages.noint);
209
+ }
210
+ break;
211
+ default:
212
+ return this._handleCallback(callback, null, messages.syntax);
213
+ }
214
+ }
215
+ if (!isNil(ttl) && !isNil(pttl)) {
216
+ return this._handleCallback(callback, null, messages.syntax);
217
+ }
218
+ if (notexist && onlyexist) {
219
+ return this._handleCallback(callback, null, messages.syntax);
220
+ }
221
+ pttl = pttl || ttl * 1000 || null;
222
+ if (!isNil(pttl)) {
223
+ pttl = Date.now() + pttl;
224
+ }
225
+ if (this._hasKey(key)) {
226
+ this._testType(key, 'string', true, callback);
227
+ if (notexist) {
228
+ return this._handleCallback(callback, retVal);
229
+ }
230
+ }
231
+ else if (onlyexist) {
232
+ return this._handleCallback(callback, retVal);
233
+ }
234
+ this.cache[key] = this._makeKey(value.toString(), 'string', pttl);
235
+ return this._handleCallback(callback, messages.ok);
227
236
  }
228
237
  /**
229
- * 返回哈希表 key 中域的数量
230
- * @param name
238
+ *
239
+ *
240
+ * @param {string} key
241
+ * @param {Function} [callback]
231
242
  * @returns {*}
243
+ * @memberof MemoryCache
232
244
  */
233
- hlen(name) {
234
- return this.wrap('hlen', [`${this.options.keyPrefix}${name}`]);
245
+ ttl(key, callback) {
246
+ let retVal = this.pttl(key);
247
+ if (retVal >= 0 || retVal <= -3) {
248
+ retVal = Math.floor(retVal / 1000);
249
+ }
250
+ return this._handleCallback(callback, retVal);
235
251
  }
236
252
  /**
237
- * 给哈希表指定key,增加increment
238
- * @param name
239
- * @param key
240
- * @param incr
253
+ *
254
+ *
255
+ * @param {string} key
256
+ * @param {number} seconds
257
+ * @param {Function} [callback]
241
258
  * @returns {*}
259
+ * @memberof MemoryCache
242
260
  */
243
- hincrby(name, key, incr = 1) {
244
- return this.wrap('hincrby', [`${this.options.keyPrefix}${name}`, key, incr]);
261
+ expire(key, seconds, callback) {
262
+ let retVal = 0;
263
+ if (this._hasKey(key)) {
264
+ this.cache[key].timeout = Date.now() + seconds * 1000;
265
+ retVal = 1;
266
+ }
267
+ return this._handleCallback(callback, retVal);
245
268
  }
246
269
  /**
247
- * 返回哈希表所有key-value
248
- * @param name
270
+ *
271
+ *
272
+ * @param {...any[]} keys
249
273
  * @returns {*}
274
+ * @memberof MemoryCache
250
275
  */
251
- hgetall(name) {
252
- return this.wrap('hgetall', [`${this.options.keyPrefix}${name}`]);
276
+ del(...keys) {
277
+ let retVal = 0;
278
+ const callback = this._retrieveCallback(keys);
279
+ // Flatten the array in case an array was passed
280
+ keys = flatten(keys);
281
+ for (let itr = 0; itr < keys.length; itr++) {
282
+ const key = keys[itr];
283
+ if (this._hasKey(key)) {
284
+ delete this.cache[key];
285
+ retVal++;
286
+ }
287
+ }
288
+ return this._handleCallback(callback, retVal);
253
289
  }
254
290
  /**
255
- * 返回哈希表所有key
256
- * @param name
291
+ *
292
+ *
293
+ * @param {...any[]} keys
257
294
  * @returns {*}
295
+ * @memberof MemoryCache
258
296
  */
259
- hkeys(name) {
260
- return this.wrap('hkeys', [`${this.options.keyPrefix}${name}`]);
297
+ exists(...keys) {
298
+ let retVal = 0;
299
+ const callback = this._retrieveCallback(keys);
300
+ for (let itr = 0; itr < keys.length; itr++) {
301
+ const key = keys[itr];
302
+ if (this._hasKey(key)) {
303
+ retVal++;
304
+ }
305
+ }
306
+ return this._handleCallback(callback, retVal);
261
307
  }
262
308
  /**
263
- * 返回哈希表所有value
264
- * @param name
309
+ *
310
+ *
311
+ * @param {string} key
312
+ * @param {Function} [callback]
265
313
  * @returns {*}
314
+ * @memberof MemoryCache
266
315
  */
267
- hvals(name) {
268
- return this.wrap('hvals', [`${this.options.keyPrefix}${name}`]);
316
+ incr(key, callback) {
317
+ let retVal = null;
318
+ try {
319
+ retVal = this._addToKey(key, 1);
320
+ }
321
+ catch (err) {
322
+ return this._handleCallback(callback, null, err);
323
+ }
324
+ return this._handleCallback(callback, retVal);
269
325
  }
270
326
  /**
271
- * 判断列表长度,若不存在则表示为空
272
- * @param name
327
+ *
328
+ *
329
+ * @param {string} key
330
+ * @param {number} amount
331
+ * @param {Function} [callback]
273
332
  * @returns {*}
333
+ * @memberof MemoryCache
274
334
  */
275
- llen(name) {
276
- return this.wrap('llen', [`${this.options.keyPrefix}${name}`]);
335
+ incrby(key, amount, callback) {
336
+ let retVal = null;
337
+ try {
338
+ retVal = this._addToKey(key, amount);
339
+ }
340
+ catch (err) {
341
+ return this._handleCallback(callback, null, err);
342
+ }
343
+ return this._handleCallback(callback, retVal);
277
344
  }
278
345
  /**
279
- * 将值插入列表表尾
280
- * @param name
281
- * @param value
346
+ *
347
+ *
348
+ * @param {string} key
349
+ * @param {Function} [callback]
282
350
  * @returns {*}
351
+ * @memberof MemoryCache
283
352
  */
284
- rpush(name, value) {
285
- return this.wrap('rpush', [`${this.options.keyPrefix}${name}`, value]);
353
+ decr(key, callback) {
354
+ let retVal = null;
355
+ try {
356
+ retVal = this._addToKey(key, -1);
357
+ }
358
+ catch (err) {
359
+ return this._handleCallback(callback, null, err);
360
+ }
361
+ return this._handleCallback(callback, retVal);
286
362
  }
287
363
  /**
288
364
  *
289
365
  *
290
- * @param {string} name
291
- * @param {(string | number)} value
366
+ * @param {string} key
367
+ * @param {number} amount
368
+ * @param {Function} [callback]
292
369
  * @returns {*}
293
- * @memberof RedisStore
370
+ * @memberof MemoryCache
294
371
  */
295
- lpush(name, value) {
296
- return this.wrap('lpush', [`${this.options.keyPrefix}${name}`, value]);
372
+ decrby(key, amount, callback) {
373
+ let retVal = null;
374
+ try {
375
+ retVal = this._addToKey(key, -amount);
376
+ }
377
+ catch (err) {
378
+ return this._handleCallback(callback, null, err);
379
+ }
380
+ return this._handleCallback(callback, retVal);
381
+ }
382
+ // ---------------------------------------
383
+ // ## Hash ##
384
+ // ---------------------------------------
385
+ hset(key, field, value, callback) {
386
+ let retVal = 0;
387
+ if (this._hasKey(key)) {
388
+ this._testType(key, 'hash', true, callback);
389
+ }
390
+ else {
391
+ this.cache[key] = this._makeKey({}, 'hash');
392
+ }
393
+ if (!this._hasField(key, field)) {
394
+ retVal = 1;
395
+ }
396
+ this._setField(key, field, value.toString());
397
+ this.persist(key);
398
+ return this._handleCallback(callback, retVal);
297
399
  }
298
400
  /**
299
- * 将列表表头取出,并去除
300
- * @param name
401
+ *
402
+ *
403
+ * @param {string} key
404
+ * @param {string} field
405
+ * @param {Function} [callback]
301
406
  * @returns {*}
407
+ * @memberof MemoryCache
302
408
  */
303
- lpop(name) {
304
- return this.wrap('lpop', [`${this.options.keyPrefix}${name}`]);
409
+ hget(key, field, callback) {
410
+ let retVal = null;
411
+ if (this._hasKey(key)) {
412
+ this._testType(key, 'hash', true, callback);
413
+ if (this._hasField(key, field)) {
414
+ retVal = this._getKey(key)[field];
415
+ }
416
+ }
417
+ return this._handleCallback(callback, retVal);
305
418
  }
306
419
  /**
307
420
  *
308
421
  *
309
- * @param {string} name
422
+ * @param {string} key
423
+ * @param {string} field
424
+ * @param {Function} [callback]
310
425
  * @returns {*}
311
- * @memberof RedisStore
426
+ * @memberof MemoryCache
312
427
  */
313
- rpop(name) {
314
- return this.wrap('rpop', [`${this.options.keyPrefix}${name}`]);
315
- }
316
- /**
317
- * 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定
318
- * @param name
319
- * @param start
320
- * @param stop
321
- * @returns {*}
322
- */
323
- lrange(name, start, stop) {
324
- return this.wrap('lrange', [`${this.options.keyPrefix}${name}`, start, stop]);
325
- }
326
- /**
327
- * 集合新增
328
- * @param name
329
- * @param value
330
- * @param timeout
331
- * @returns {*}
332
- */
333
- sadd(name, value, timeout) {
334
- const setP = [this.wrap('sadd', [`${this.options.keyPrefix}${name}`, value])];
335
- if (typeof timeout !== 'number') {
336
- setP.push(this.wrap('expire', [`${this.options.keyPrefix}${name}`, timeout]));
337
- }
338
- return Promise.all(setP);
339
- }
340
- /**
341
- * 返回集合的基数(集合中元素的数量)
342
- * @param name
343
- * @returns {*}
344
- */
345
- scard(name) {
346
- return this.wrap('scard', [`${this.options.keyPrefix}${name}`]);
347
- }
348
- /**
349
- * 判断 member 元素是否集合的成员
350
- * @param name
351
- * @param key
352
- * @returns {*}
353
- */
354
- sismember(name, key) {
355
- return this.wrap('sismember', [`${this.options.keyPrefix}${name}`, key]);
356
- }
357
- /**
358
- * 返回集合中的所有成员
359
- * @param name
360
- * @returns {*}
361
- */
362
- smembers(name) {
363
- return this.wrap('smembers', [`${this.options.keyPrefix}${name}`]);
364
- }
365
- /**
366
- * 移除并返回集合中的一个随机元素
367
- * @param name
368
- * @returns {*}
369
- */
370
- spop(name) {
371
- return this.wrap('spop', [`${this.options.keyPrefix}${name}`]);
372
- }
373
- /**
374
- * 移除集合 key 中的一个 member 元素
375
- * @param name
376
- * @param key
377
- * @returns {*}
378
- */
379
- srem(name, key) {
380
- return this.wrap('srem', [`${this.options.keyPrefix}${name}`, key]);
381
- }
382
- /**
383
- * 将 member 元素从 source 集合移动到 destination 集合
384
- * @param source
385
- * @param destination
386
- * @param member
387
- * @returns {*}
388
- */
389
- smove(source, destination, member) {
390
- return this.wrap('smove', [`${this.options.keyPrefix}${source}`, `${this.options.keyPrefix}${destination}`, member]);
391
- }
392
- }
393
-
394
- /*
395
- * @Description:
396
- * @Usage:
397
- * @Author: richen
398
- * @Date: 2021-12-02 11:03:20
399
- * @LastEditTime: 2023-01-13 11:25:09
400
- */
401
- /**
402
- *
403
- *
404
- * @enum {number}
405
- */
406
- var messages;
407
- (function (messages) {
408
- messages["ok"] = "OK";
409
- messages["queued"] = "QUEUED";
410
- messages["pong"] = "PONG";
411
- messages["noint"] = "ERR value is not an integer or out of range";
412
- messages["nofloat"] = "ERR value is not an float or out of range";
413
- messages["nokey"] = "ERR no such key";
414
- messages["nomultiinmulti"] = "ERR MULTI calls can not be nested";
415
- messages["nomultiexec"] = "ERR EXEC without MULTI";
416
- messages["nomultidiscard"] = "ERR DISCARD without MULTI";
417
- messages["busykey"] = "ERR target key name is busy";
418
- messages["syntax"] = "ERR syntax error";
419
- messages["unsupported"] = "MemoryCache does not support that operation";
420
- messages["wrongTypeOp"] = "WRONGTYPE Operation against a key holding the wrong kind of value";
421
- messages["wrongPayload"] = "DUMP payload version or checksum are wrong";
422
- messages["wrongArgCount"] = "ERR wrong number of arguments for '%0' command";
423
- messages["bitopnotWrongCount"] = "ERR BITOP NOT must be called with a single source key";
424
- messages["indexOutOfRange"] = "ERR index out of range";
425
- messages["invalidLexRange"] = "ERR min or max not valid string range item";
426
- messages["invalidDBIndex"] = "ERR invalid DB index";
427
- messages["invalidDBIndexNX"] = "ERR invalid DB index, '%0' does not exist";
428
- messages["mutuallyExclusiveNXXX"] = "ERR XX and NX options at the same time are not compatible";
429
- })(messages || (messages = {}));
430
- class MemoryCache extends EventEmitter {
431
- /**
432
- * Creates an instance of MemoryCache.
433
- * @param {*} options
434
- * @memberof MemoryCache
435
- */
436
- constructor(options) {
437
- super();
438
- this.databases = Object.create({});
439
- this.options = { ...{ database: "0" }, ...options };
440
- this.currentDBIndex = 0;
441
- this.connected = false;
442
- this.lastSave = Date.now();
443
- this.multiMode = false;
428
+ hexists(key, field, callback) {
429
+ let retVal = 0;
430
+ if (this._hasKey(key)) {
431
+ this._testType(key, 'hash', true, callback);
432
+ if (this._hasField(key, field)) {
433
+ retVal = 1;
434
+ }
435
+ }
436
+ return this._handleCallback(callback, retVal);
444
437
  }
445
438
  /**
446
439
  *
447
440
  *
441
+ * @param {string} key
442
+ * @param {...any[]} fields
448
443
  * @returns {*}
449
444
  * @memberof MemoryCache
450
445
  */
451
- createClient() {
452
- this.databases[this.options.database] = Object.create({});
453
- this.cache = this.databases[this.options.database];
454
- this.connected = true;
455
- // exit multi mode if we are in it
456
- this.discard(null, true);
457
- this.emit('connect');
458
- this.emit('ready');
459
- return this;
446
+ hdel(key, ...fields) {
447
+ let retVal = 0;
448
+ const callback = this._retrieveCallback(fields);
449
+ if (this._hasKey(key)) {
450
+ this._testType(key, 'hash', true, callback);
451
+ for (let itr = 0; itr < fields.length; itr++) {
452
+ const field = fields[itr];
453
+ if (this._hasField(key, field)) {
454
+ delete this.cache[key].value[field];
455
+ retVal++;
456
+ }
457
+ }
458
+ }
459
+ return this._handleCallback(callback, retVal);
460
460
  }
461
461
  /**
462
462
  *
463
463
  *
464
+ * @param {string} key
465
+ * @param {Function} [callback]
464
466
  * @returns {*}
465
467
  * @memberof MemoryCache
466
468
  */
467
- quit() {
468
- this.connected = false;
469
- // exit multi mode if we are in it
470
- this.discard(null, true);
471
- this.emit('end');
472
- return this;
469
+ hlen(key, callback) {
470
+ const retVal = this.hkeys(key).length;
471
+ return this._handleCallback(callback, retVal);
473
472
  }
474
473
  /**
475
474
  *
476
475
  *
476
+ * @param {string} key
477
+ * @param {string} field
478
+ * @param {*} value
479
+ * @param {Function} [callback]
477
480
  * @returns {*}
478
481
  * @memberof MemoryCache
479
482
  */
480
- end() {
481
- return this.quit();
483
+ hincrby(key, field, value, callback) {
484
+ let retVal;
485
+ try {
486
+ retVal = this._addToField(key, field, value, false);
487
+ }
488
+ catch (err) {
489
+ return this._handleCallback(callback, null, err);
490
+ }
491
+ return this._handleCallback(callback, retVal);
482
492
  }
483
493
  /**
484
494
  *
485
495
  *
486
- * @param {string} message
496
+ * @param {string} key
487
497
  * @param {Function} [callback]
488
498
  * @returns {*}
489
499
  * @memberof MemoryCache
490
500
  */
491
- echo(message, callback) {
492
- return this._handleCallback(callback, message);
501
+ hgetall(key, callback) {
502
+ let retVals = {};
503
+ if (this._hasKey(key)) {
504
+ this._testType(key, 'hash', true, callback);
505
+ retVals = this._getKey(key);
506
+ }
507
+ return this._handleCallback(callback, retVals);
508
+ }
509
+ /**
510
+ *
511
+ *
512
+ * @param {string} key
513
+ * @param {Function} [callback]
514
+ * @returns {*}
515
+ * @memberof MemoryCache
516
+ */
517
+ hkeys(key, callback) {
518
+ let retVals = [];
519
+ if (this._hasKey(key)) {
520
+ this._testType(key, 'hash', true, callback);
521
+ retVals = Object.keys(this._getKey(key));
522
+ }
523
+ return this._handleCallback(callback, retVals);
493
524
  }
494
525
  /**
495
526
  *
496
527
  *
497
- * @param {string} message
528
+ * @param {string} key
498
529
  * @param {Function} [callback]
499
530
  * @returns {*}
500
531
  * @memberof MemoryCache
501
532
  */
502
- ping(message, callback) {
503
- message = message || messages.pong;
504
- return this._handleCallback(callback, message);
533
+ hvals(key, callback) {
534
+ let retVals = [];
535
+ if (this._hasKey(key)) {
536
+ this._testType(key, 'hash', true, callback);
537
+ retVals = Object.values(this._getKey(key));
538
+ }
539
+ return this._handleCallback(callback, retVals);
505
540
  }
541
+ // ---------------------------------------
542
+ // Lists (Array / Queue / Stack)
543
+ // ---------------------------------------
506
544
  /**
507
545
  *
508
546
  *
509
- * @param {string} password
547
+ * @param {string} key
510
548
  * @param {Function} [callback]
511
549
  * @returns {*}
512
550
  * @memberof MemoryCache
513
551
  */
514
- auth(password, callback) {
515
- return this._handleCallback(callback, messages.ok);
552
+ llen(key, callback) {
553
+ let retVal = 0;
554
+ if (this._hasKey(key)) {
555
+ this._testType(key, 'list', true, callback);
556
+ retVal = this._getKey(key).length || 0;
557
+ }
558
+ return this._handleCallback(callback, retVal);
516
559
  }
517
560
  /**
518
561
  *
519
562
  *
520
- * @param {number} dbIndex
563
+ * @param {string} key
564
+ * @param {(string | number)} value
521
565
  * @param {Function} [callback]
522
566
  * @returns {*}
523
567
  * @memberof MemoryCache
524
568
  */
525
- select(dbIndex, callback) {
526
- if (!helper.isNumber(dbIndex)) {
527
- return this._handleCallback(callback, null, messages.invalidDBIndex);
528
- }
529
- if (!this.databases.hasOwnProperty(dbIndex)) {
530
- this.databases[dbIndex] = Object.create({});
531
- }
532
- this.multiMode = false;
533
- this.currentDBIndex = dbIndex;
534
- this.cache = this.databases[dbIndex];
535
- return this._handleCallback(callback, messages.ok);
536
- }
537
- // ---------------------------------------
538
- // Keys
539
- // ---------------------------------------
540
- get(key, callback) {
541
- let retVal = null;
569
+ rpush(key, value, callback) {
570
+ let retVal = 0;
542
571
  if (this._hasKey(key)) {
543
- this._testType(key, 'string', true, callback);
544
- retVal = this._getKey(key);
572
+ this._testType(key, 'list', true, callback);
545
573
  }
574
+ else {
575
+ this.cache[key] = this._makeKey([], 'list');
576
+ }
577
+ const val = this._getKey(key);
578
+ val.push(value);
579
+ this._setKey(key, val);
580
+ retVal = val.length;
546
581
  return this._handleCallback(callback, retVal);
547
582
  }
548
583
  /**
549
- * set(key, value, ttl, pttl, notexist, onlyexist, callback)
584
+ *
550
585
  *
551
586
  * @param {string} key
552
587
  * @param {(string | number)} value
553
- * @param {...any[]} params
588
+ * @param {Function} [callback]
554
589
  * @returns {*}
555
590
  * @memberof MemoryCache
556
591
  */
557
- set(key, value, ...params) {
558
- const retVal = null;
559
- params = flatten(params);
560
- const callback = this._retrieveCallback(params);
561
- let ttl, pttl, notexist, onlyexist;
562
- // parse parameters
563
- while (params.length > 0) {
564
- const param = params.shift();
565
- switch (param.toString().toLowerCase()) {
566
- case 'nx':
567
- notexist = true;
568
- break;
569
- case 'xx':
570
- onlyexist = true;
571
- break;
572
- case 'ex':
573
- if (params.length === 0) {
574
- return this._handleCallback(callback, null, messages.syntax);
575
- }
576
- ttl = parseInt(params.shift());
577
- if (isNaN(ttl)) {
578
- return this._handleCallback(callback, null, messages.noint);
579
- }
580
- break;
581
- case 'px':
582
- if (params.length === 0) {
583
- return this._handleCallback(callback, null, messages.syntax);
584
- }
585
- pttl = parseInt(params.shift());
586
- if (isNaN(pttl)) {
587
- return this._handleCallback(callback, null, messages.noint);
588
- }
589
- break;
590
- default:
591
- return this._handleCallback(callback, null, messages.syntax);
592
- }
593
- }
594
- if (!isNil(ttl) && !isNil(pttl)) {
595
- return this._handleCallback(callback, null, messages.syntax);
596
- }
597
- if (notexist && onlyexist) {
598
- return this._handleCallback(callback, null, messages.syntax);
599
- }
600
- pttl = pttl || ttl * 1000 || null;
601
- if (!isNil(pttl)) {
602
- pttl = Date.now() + pttl;
603
- }
592
+ lpush(key, value, callback) {
593
+ let retVal = 0;
604
594
  if (this._hasKey(key)) {
605
- this._testType(key, 'string', true, callback);
606
- if (notexist) {
607
- return this._handleCallback(callback, retVal);
608
- }
595
+ this._testType(key, 'list', true, callback);
609
596
  }
610
- else if (onlyexist) {
611
- return this._handleCallback(callback, retVal);
597
+ else {
598
+ this.cache[key] = this._makeKey([], 'list');
612
599
  }
613
- this.cache[key] = this._makeKey(value.toString(), 'string', pttl);
614
- return this._handleCallback(callback, messages.ok);
600
+ const val = this._getKey(key);
601
+ val.splice(0, 0, value);
602
+ this._setKey(key, val);
603
+ retVal = val.length;
604
+ return this._handleCallback(callback, retVal);
615
605
  }
616
606
  /**
617
607
  *
@@ -621,10 +611,13 @@ class MemoryCache extends EventEmitter {
621
611
  * @returns {*}
622
612
  * @memberof MemoryCache
623
613
  */
624
- ttl(key, callback) {
625
- let retVal = this.pttl(key);
626
- if (retVal >= 0 || retVal <= -3) {
627
- retVal = Math.floor(retVal / 1000);
614
+ lpop(key, callback) {
615
+ let retVal = null;
616
+ if (this._hasKey(key)) {
617
+ this._testType(key, 'list', true, callback);
618
+ const val = this._getKey(key);
619
+ retVal = val.shift();
620
+ this._setKey(key, val);
628
621
  }
629
622
  return this._handleCallback(callback, retVal);
630
623
  }
@@ -632,56 +625,83 @@ class MemoryCache extends EventEmitter {
632
625
  *
633
626
  *
634
627
  * @param {string} key
635
- * @param {number} seconds
636
628
  * @param {Function} [callback]
637
629
  * @returns {*}
638
630
  * @memberof MemoryCache
639
631
  */
640
- expire(key, seconds, callback) {
641
- let retVal = 0;
632
+ rpop(key, callback) {
633
+ let retVal = null;
642
634
  if (this._hasKey(key)) {
643
- this.cache[key].timeout = Date.now() + seconds * 1000;
644
- retVal = 1;
635
+ this._testType(key, 'list', true, callback);
636
+ const val = this._getKey(key);
637
+ retVal = val.pop();
638
+ this._setKey(key, val);
645
639
  }
646
640
  return this._handleCallback(callback, retVal);
647
641
  }
648
642
  /**
649
643
  *
650
644
  *
651
- * @param {...any[]} keys
645
+ * @param {string} key
646
+ * @param {number} start
647
+ * @param {number} stop
648
+ * @param {Function} [callback]
652
649
  * @returns {*}
653
650
  * @memberof MemoryCache
654
651
  */
655
- del(...keys) {
656
- let retVal = 0;
657
- const callback = this._retrieveCallback(keys);
658
- // Flatten the array in case an array was passed
659
- keys = flatten(keys);
660
- for (let itr = 0; itr < keys.length; itr++) {
661
- const key = keys[itr];
662
- if (this._hasKey(key)) {
663
- delete this.cache[key];
664
- retVal++;
652
+ lrange(key, start, stop, callback) {
653
+ const retVal = [];
654
+ if (this._hasKey(key)) {
655
+ this._testType(key, 'list', true, callback);
656
+ const val = this._getKey(key);
657
+ const length = val.length;
658
+ if (stop < 0) {
659
+ stop = length + stop;
660
+ }
661
+ if (start < 0) {
662
+ start = length + start;
663
+ }
664
+ if (start < 0) {
665
+ start = 0;
666
+ }
667
+ if (stop >= length) {
668
+ stop = length - 1;
669
+ }
670
+ if (stop >= 0 && stop >= start) {
671
+ const size = stop - start + 1;
672
+ for (let itr = start; itr < size; itr++) {
673
+ retVal.push(val[itr]);
674
+ }
665
675
  }
666
676
  }
667
677
  return this._handleCallback(callback, retVal);
668
678
  }
679
+ // ---------------------------------------
680
+ // ## Sets (Unique Lists)##
681
+ // ---------------------------------------
669
682
  /**
670
683
  *
671
684
  *
672
- * @param {...any[]} keys
685
+ * @param {string} key
686
+ * @param {...any[]} members
673
687
  * @returns {*}
674
688
  * @memberof MemoryCache
675
689
  */
676
- exists(...keys) {
690
+ sadd(key, ...members) {
677
691
  let retVal = 0;
678
- const callback = this._retrieveCallback(keys);
679
- for (let itr = 0; itr < keys.length; itr++) {
680
- const key = keys[itr];
681
- if (this._hasKey(key)) {
682
- retVal++;
683
- }
692
+ const callback = this._retrieveCallback(members);
693
+ if (this._hasKey(key)) {
694
+ this._testType(key, 'set', true, callback);
695
+ }
696
+ else {
697
+ this.cache[key] = this._makeKey([], 'set');
684
698
  }
699
+ const val = this._getKey(key);
700
+ const length = val.length;
701
+ const nval = union(val, members);
702
+ const newlength = nval.length;
703
+ retVal = newlength - length;
704
+ this._setKey(key, nval);
685
705
  return this._handleCallback(callback, retVal);
686
706
  }
687
707
  /**
@@ -692,13 +712,11 @@ class MemoryCache extends EventEmitter {
692
712
  * @returns {*}
693
713
  * @memberof MemoryCache
694
714
  */
695
- incr(key, callback) {
696
- let retVal = null;
697
- try {
698
- retVal = this._addToKey(key, 1);
699
- }
700
- catch (err) {
701
- return this._handleCallback(callback, null, err);
715
+ scard(key, callback) {
716
+ let retVal = 0;
717
+ if (this._hasKey(key)) {
718
+ this._testType(key, 'set', true, callback);
719
+ retVal = this._getKey(key).length;
702
720
  }
703
721
  return this._handleCallback(callback, retVal);
704
722
  }
@@ -706,18 +724,19 @@ class MemoryCache extends EventEmitter {
706
724
  *
707
725
  *
708
726
  * @param {string} key
709
- * @param {number} amount
727
+ * @param {string} member
710
728
  * @param {Function} [callback]
711
729
  * @returns {*}
712
730
  * @memberof MemoryCache
713
731
  */
714
- incrby(key, amount, callback) {
715
- let retVal = null;
716
- try {
717
- retVal = this._addToKey(key, amount);
718
- }
719
- catch (err) {
720
- return this._handleCallback(callback, null, err);
732
+ sismember(key, member, callback) {
733
+ let retVal = 0;
734
+ if (this._hasKey(key)) {
735
+ this._testType(key, 'set', true, callback);
736
+ const val = this._getKey(key);
737
+ if (val.includes(member)) {
738
+ retVal = 1;
739
+ }
721
740
  }
722
741
  return this._handleCallback(callback, retVal);
723
742
  }
@@ -729,13 +748,11 @@ class MemoryCache extends EventEmitter {
729
748
  * @returns {*}
730
749
  * @memberof MemoryCache
731
750
  */
732
- decr(key, callback) {
733
- let retVal = null;
734
- try {
735
- retVal = this._addToKey(key, -1);
736
- }
737
- catch (err) {
738
- return this._handleCallback(callback, null, err);
751
+ smembers(key, callback) {
752
+ let retVal = [];
753
+ if (this._hasKey(key)) {
754
+ this._testType(key, 'set', true, callback);
755
+ retVal = this._getKey(key);
739
756
  }
740
757
  return this._handleCallback(callback, retVal);
741
758
  }
@@ -743,1144 +760,1113 @@ class MemoryCache extends EventEmitter {
743
760
  *
744
761
  *
745
762
  * @param {string} key
746
- * @param {number} amount
763
+ * @param {number} [count]
747
764
  * @param {Function} [callback]
748
765
  * @returns {*}
749
766
  * @memberof MemoryCache
750
767
  */
751
- decrby(key, amount, callback) {
768
+ spop(key, count, callback) {
752
769
  let retVal = null;
753
- try {
754
- retVal = this._addToKey(key, -amount);
755
- }
756
- catch (err) {
757
- return this._handleCallback(callback, null, err);
770
+ count = count || 1;
771
+ if (isNaN(count)) {
772
+ return this._handleCallback(callback, null, messages.noint);
758
773
  }
759
- return this._handleCallback(callback, retVal);
760
- }
761
- // ---------------------------------------
762
- // ## Hash ##
763
- // ---------------------------------------
764
- hset(key, field, value, callback) {
765
- let retVal = 0;
766
774
  if (this._hasKey(key)) {
767
- this._testType(key, 'hash', true, callback);
768
- }
769
- else {
770
- this.cache[key] = this._makeKey({}, 'hash');
771
- }
772
- if (!this._hasField(key, field)) {
773
- retVal = 1;
775
+ retVal = [];
776
+ this._testType(key, 'set', true, callback);
777
+ const val = this._getKey(key);
778
+ const length = val.length;
779
+ count = count > length ? length : count;
780
+ for (let itr = 0; itr < count; itr++) {
781
+ retVal.push(val.pop());
782
+ }
774
783
  }
775
- this._setField(key, field, value.toString());
776
- this.persist(key);
777
784
  return this._handleCallback(callback, retVal);
778
785
  }
779
786
  /**
780
787
  *
781
788
  *
782
789
  * @param {string} key
783
- * @param {string} field
784
- * @param {Function} [callback]
790
+ * @param {...any[]} members
785
791
  * @returns {*}
786
792
  * @memberof MemoryCache
787
793
  */
788
- hget(key, field, callback) {
789
- let retVal = null;
794
+ srem(key, ...members) {
795
+ let retVal = 0;
796
+ const callback = this._retrieveCallback(members);
790
797
  if (this._hasKey(key)) {
791
- this._testType(key, 'hash', true, callback);
792
- if (this._hasField(key, field)) {
793
- retVal = this._getKey(key)[field];
798
+ this._testType(key, 'set', true, callback);
799
+ const val = this._getKey(key);
800
+ for (const index in members) {
801
+ if (members.hasOwnProperty(index)) {
802
+ const member = members[index];
803
+ const idx = val.indexOf(member);
804
+ if (idx !== -1) {
805
+ val.splice(idx, 1);
806
+ retVal++;
807
+ }
808
+ }
794
809
  }
810
+ this._setKey(key, val);
795
811
  }
796
812
  return this._handleCallback(callback, retVal);
797
813
  }
798
814
  /**
799
815
  *
800
816
  *
801
- * @param {string} key
802
- * @param {string} field
817
+ * @param {string} sourcekey
818
+ * @param {string} destkey
819
+ * @param {string} member
803
820
  * @param {Function} [callback]
804
821
  * @returns {*}
805
822
  * @memberof MemoryCache
806
823
  */
807
- hexists(key, field, callback) {
824
+ smove(sourcekey, destkey, member, callback) {
808
825
  let retVal = 0;
809
- if (this._hasKey(key)) {
810
- this._testType(key, 'hash', true, callback);
811
- if (this._hasField(key, field)) {
826
+ if (this._hasKey(sourcekey)) {
827
+ this._testType(sourcekey, 'set', true, callback);
828
+ const val = this._getKey(sourcekey);
829
+ const idx = val.indexOf(member);
830
+ if (idx !== -1) {
831
+ this.sadd(destkey, member);
832
+ val.splice(idx, 1);
812
833
  retVal = 1;
813
834
  }
814
835
  }
815
836
  return this._handleCallback(callback, retVal);
816
837
  }
838
+ // ---------------------------------------
839
+ // ## Transactions (Atomic) ##
840
+ // ---------------------------------------
841
+ // TODO: Transaction Queues watch and unwatch
842
+ // https://redis.io/topics/transactions
843
+ // This can be accomplished by temporarily swapping this.cache to a temporary copy of the current statement
844
+ // holding and then using __.merge on actual this.cache with the temp storage.
845
+ discard(callback, silent) {
846
+ // Clear the queue mode, drain the queue, empty the watch list
847
+ if (this.multiMode) {
848
+ this.cache = this.databases[this.currentDBIndex];
849
+ this.multiMode = false;
850
+ this.responseMessages = [];
851
+ }
852
+ else if (!silent) {
853
+ return this._handleCallback(callback, null, messages.nomultidiscard);
854
+ }
855
+ return this._handleCallback(callback, messages.ok);
856
+ }
857
+ // ---------------------------------------
858
+ // ## Internal - Key ##
859
+ // ---------------------------------------
817
860
  /**
818
861
  *
819
862
  *
820
863
  * @param {string} key
821
- * @param {...any[]} fields
864
+ * @param {Function} [callback]
822
865
  * @returns {*}
823
866
  * @memberof MemoryCache
824
867
  */
825
- hdel(key, ...fields) {
826
- let retVal = 0;
827
- const callback = this._retrieveCallback(fields);
868
+ pttl(key, callback) {
869
+ let retVal = -2;
828
870
  if (this._hasKey(key)) {
829
- this._testType(key, 'hash', true, callback);
830
- for (let itr = 0; itr < fields.length; itr++) {
831
- const field = fields[itr];
832
- if (this._hasField(key, field)) {
833
- delete this.cache[key].value[field];
834
- retVal++;
871
+ if (!isNil(this.cache[key].timeout)) {
872
+ retVal = this.cache[key].timeout - Date.now();
873
+ // Prevent unexpected errors if the actual ttl just happens to be -2 or -1
874
+ if (retVal < 0 && retVal > -3) {
875
+ retVal = -3;
835
876
  }
836
877
  }
878
+ else {
879
+ retVal = -1;
880
+ }
837
881
  }
838
882
  return this._handleCallback(callback, retVal);
839
883
  }
840
884
  /**
841
885
  *
842
886
  *
887
+ * @private
843
888
  * @param {string} key
844
889
  * @param {Function} [callback]
845
890
  * @returns {*}
846
891
  * @memberof MemoryCache
847
892
  */
848
- hlen(key, callback) {
849
- const retVal = this.hkeys(key).length;
893
+ persist(key, callback) {
894
+ let retVal = 0;
895
+ if (this._hasKey(key)) {
896
+ if (!isNil(this._key(key).timeout)) {
897
+ this._key(key).timeout = null;
898
+ retVal = 1;
899
+ }
900
+ }
850
901
  return this._handleCallback(callback, retVal);
851
902
  }
852
903
  /**
853
904
  *
854
905
  *
906
+ * @private
855
907
  * @param {string} key
856
- * @param {string} field
857
- * @param {*} value
858
- * @param {Function} [callback]
859
- * @returns {*}
908
+ * @returns {*} {boolean}
860
909
  * @memberof MemoryCache
861
910
  */
862
- hincrby(key, field, value, callback) {
863
- let retVal;
864
- try {
865
- retVal = this._addToField(key, field, value, false);
866
- }
867
- catch (err) {
868
- return this._handleCallback(callback, null, err);
869
- }
870
- return this._handleCallback(callback, retVal);
911
+ _hasKey(key) {
912
+ return this.cache.hasOwnProperty(key);
871
913
  }
872
914
  /**
873
915
  *
874
916
  *
875
- * @param {string} key
876
- * @param {Function} [callback]
917
+ * @private
918
+ * @param {*} value
919
+ * @param {string} type
920
+ * @param {number} timeout
877
921
  * @returns {*}
878
922
  * @memberof MemoryCache
879
923
  */
880
- hgetall(key, callback) {
881
- let retVals = {};
882
- if (this._hasKey(key)) {
883
- this._testType(key, 'hash', true, callback);
884
- retVals = this._getKey(key);
885
- }
886
- return this._handleCallback(callback, retVals);
887
- }
888
- /**
889
- *
890
- *
891
- * @param {string} key
892
- * @param {Function} [callback]
893
- * @returns {*}
894
- * @memberof MemoryCache
895
- */
896
- hkeys(key, callback) {
897
- let retVals = [];
898
- if (this._hasKey(key)) {
899
- this._testType(key, 'hash', true, callback);
900
- retVals = Object.keys(this._getKey(key));
901
- }
902
- return this._handleCallback(callback, retVals);
924
+ _makeKey(value, type, timeout) {
925
+ return { value: value, type: type, timeout: timeout || null, lastAccess: Date.now() };
903
926
  }
904
927
  /**
905
928
  *
906
929
  *
930
+ * @private
907
931
  * @param {string} key
908
- * @param {Function} [callback]
909
932
  * @returns {*}
910
933
  * @memberof MemoryCache
911
934
  */
912
- hvals(key, callback) {
913
- let retVals = [];
914
- if (this._hasKey(key)) {
915
- this._testType(key, 'hash', true, callback);
916
- retVals = Object.values(this._getKey(key));
917
- }
918
- return this._handleCallback(callback, retVals);
935
+ _key(key) {
936
+ this.cache[key].lastAccess = Date.now();
937
+ return this.cache[key];
919
938
  }
920
- // ---------------------------------------
921
- // Lists (Array / Queue / Stack)
922
- // ---------------------------------------
923
939
  /**
924
940
  *
925
941
  *
942
+ * @private
926
943
  * @param {string} key
944
+ * @param {number} amount
927
945
  * @param {Function} [callback]
928
946
  * @returns {*}
929
947
  * @memberof MemoryCache
930
948
  */
931
- llen(key, callback) {
932
- let retVal = 0;
949
+ _addToKey(key, amount, callback) {
950
+ let keyValue = 0;
951
+ if (isNaN(amount) || isNil(amount)) {
952
+ return this._handleCallback(callback, null, messages.noint);
953
+ }
933
954
  if (this._hasKey(key)) {
934
- this._testType(key, 'list', true, callback);
935
- retVal = this._getKey(key).length || 0;
955
+ this._testType(key, 'string', true, callback);
956
+ keyValue = parseInt(this._getKey(key));
957
+ if (isNaN(keyValue) || isNil(keyValue)) {
958
+ return this._handleCallback(callback, null, messages.noint);
959
+ }
936
960
  }
937
- return this._handleCallback(callback, retVal);
961
+ else {
962
+ this.cache[key] = this._makeKey('0', 'string');
963
+ }
964
+ const val = keyValue + amount;
965
+ this._setKey(key, val.toString());
966
+ return val;
938
967
  }
939
968
  /**
940
969
  *
941
970
  *
971
+ * @private
942
972
  * @param {string} key
943
- * @param {(string | number)} value
973
+ * @param {string} type
974
+ * @param {boolean} [throwError]
944
975
  * @param {Function} [callback]
945
976
  * @returns {*}
946
977
  * @memberof MemoryCache
947
978
  */
948
- rpush(key, value, callback) {
949
- let retVal = 0;
950
- if (this._hasKey(key)) {
951
- this._testType(key, 'list', true, callback);
952
- }
953
- else {
954
- this.cache[key] = this._makeKey([], 'list');
979
+ _testType(key, type, throwError, callback) {
980
+ throwError = !!throwError;
981
+ const keyType = this._key(key).type;
982
+ if (keyType !== type) {
983
+ if (throwError) {
984
+ return this._handleCallback(callback, null, messages.wrongTypeOp);
985
+ }
986
+ return false;
955
987
  }
956
- const val = this._getKey(key);
957
- val.push(value);
958
- this._setKey(key, val);
959
- retVal = val.length;
960
- return this._handleCallback(callback, retVal);
988
+ return true;
961
989
  }
962
990
  /**
963
991
  *
964
992
  *
993
+ * @private
965
994
  * @param {string} key
966
- * @param {(string | number)} value
967
- * @param {Function} [callback]
968
995
  * @returns {*}
969
996
  * @memberof MemoryCache
970
997
  */
971
- lpush(key, value, callback) {
972
- let retVal = 0;
973
- if (this._hasKey(key)) {
974
- this._testType(key, 'list', true, callback);
975
- }
976
- else {
977
- this.cache[key] = this._makeKey([], 'list');
998
+ _getKey(key) {
999
+ const _key = this._key(key) || {};
1000
+ if (_key.timeout && _key.timeout <= Date.now()) {
1001
+ this.del(key);
1002
+ return null;
978
1003
  }
979
- const val = this._getKey(key);
980
- val.splice(0, 0, value);
981
- this._setKey(key, val);
982
- retVal = val.length;
983
- return this._handleCallback(callback, retVal);
1004
+ return _key.value;
984
1005
  }
985
1006
  /**
986
1007
  *
987
1008
  *
1009
+ * @private
988
1010
  * @param {string} key
989
- * @param {Function} [callback]
990
- * @returns {*}
1011
+ * @param {(number | string)} value
991
1012
  * @memberof MemoryCache
992
1013
  */
993
- lpop(key, callback) {
994
- let retVal = null;
995
- if (this._hasKey(key)) {
996
- this._testType(key, 'list', true, callback);
997
- const val = this._getKey(key);
998
- retVal = val.shift();
999
- this._setKey(key, val);
1000
- }
1001
- return this._handleCallback(callback, retVal);
1014
+ _setKey(key, value) {
1015
+ this.cache[key].value = value;
1016
+ this.cache[key].lastAccess = Date.now();
1002
1017
  }
1003
1018
  /**
1004
1019
  *
1005
1020
  *
1021
+ * @private
1006
1022
  * @param {string} key
1023
+ * @param {string} field
1024
+ * @param {number} [amount]
1025
+ * @param {boolean} [useFloat]
1007
1026
  * @param {Function} [callback]
1008
1027
  * @returns {*}
1009
1028
  * @memberof MemoryCache
1010
1029
  */
1011
- rpop(key, callback) {
1012
- let retVal = null;
1030
+ _addToField(key, field, amount, useFloat, callback) {
1031
+ useFloat = useFloat || false;
1032
+ let fieldValue = useFloat ? 0.0 : 0;
1033
+ let value = 0;
1034
+ if (isNaN(amount) || isNil(amount)) {
1035
+ return this._handleCallback(callback, null, useFloat ? messages.nofloat : messages.noint);
1036
+ }
1013
1037
  if (this._hasKey(key)) {
1014
- this._testType(key, 'list', true, callback);
1015
- const val = this._getKey(key);
1016
- retVal = val.pop();
1017
- this._setKey(key, val);
1038
+ this._testType(key, 'hash', true, callback);
1039
+ if (this._hasField(key, field)) {
1040
+ value = this._getField(key, field);
1041
+ }
1018
1042
  }
1019
- return this._handleCallback(callback, retVal);
1043
+ else {
1044
+ this.cache[key] = this._makeKey({}, 'hash');
1045
+ }
1046
+ fieldValue = useFloat ? parseFloat(`${value}`) : parseInt(`${value}`);
1047
+ amount = useFloat ? parseFloat(`${amount}`) : parseInt(`${amount}`);
1048
+ if (isNaN(fieldValue) || isNil(fieldValue)) {
1049
+ return this._handleCallback(callback, null, useFloat ? messages.nofloat : messages.noint);
1050
+ }
1051
+ fieldValue += amount;
1052
+ this._setField(key, field, fieldValue.toString());
1053
+ return fieldValue;
1020
1054
  }
1021
1055
  /**
1022
1056
  *
1023
1057
  *
1058
+ * @private
1024
1059
  * @param {string} key
1025
- * @param {number} start
1026
- * @param {number} stop
1027
- * @param {Function} [callback]
1060
+ * @param {string} field
1028
1061
  * @returns {*}
1029
1062
  * @memberof MemoryCache
1030
1063
  */
1031
- lrange(key, start, stop, callback) {
1032
- const retVal = [];
1033
- if (this._hasKey(key)) {
1034
- this._testType(key, 'list', true, callback);
1035
- const val = this._getKey(key);
1036
- const length = val.length;
1037
- if (stop < 0) {
1038
- stop = length + stop;
1039
- }
1040
- if (start < 0) {
1041
- start = length + start;
1042
- }
1043
- if (start < 0) {
1044
- start = 0;
1045
- }
1046
- if (stop >= length) {
1047
- stop = length - 1;
1048
- }
1049
- if (stop >= 0 && stop >= start) {
1050
- const size = stop - start + 1;
1051
- for (let itr = start; itr < size; itr++) {
1052
- retVal.push(val[itr]);
1053
- }
1054
- }
1055
- }
1056
- return this._handleCallback(callback, retVal);
1064
+ _getField(key, field) {
1065
+ return this._getKey(key)[field];
1057
1066
  }
1058
- // ---------------------------------------
1059
- // ## Sets (Unique Lists)##
1060
- // ---------------------------------------
1061
1067
  /**
1062
1068
  *
1063
1069
  *
1070
+ * @private
1064
1071
  * @param {string} key
1065
- * @param {...any[]} members
1066
- * @returns {*}
1072
+ * @param {string} field
1073
+ * @returns {*} {boolean}
1067
1074
  * @memberof MemoryCache
1068
1075
  */
1069
- sadd(key, ...members) {
1070
- let retVal = 0;
1071
- const callback = this._retrieveCallback(members);
1072
- if (this._hasKey(key)) {
1073
- this._testType(key, 'set', true, callback);
1074
- }
1075
- else {
1076
- this.cache[key] = this._makeKey([], 'set');
1076
+ _hasField(key, field) {
1077
+ let retVal = false;
1078
+ if (key && field) {
1079
+ const ky = this._getKey(key);
1080
+ if (ky) {
1081
+ retVal = ky.hasOwnProperty(field);
1082
+ }
1077
1083
  }
1078
- const val = this._getKey(key);
1079
- const length = val.length;
1080
- const nval = union(val, members);
1081
- const newlength = nval.length;
1082
- retVal = newlength - length;
1083
- this._setKey(key, nval);
1084
- return this._handleCallback(callback, retVal);
1084
+ return retVal;
1085
1085
  }
1086
1086
  /**
1087
1087
  *
1088
1088
  *
1089
1089
  * @param {string} key
1090
- * @param {Function} [callback]
1091
- * @returns {*}
1090
+ * @param {string} field
1091
+ * @param {*} value
1092
1092
  * @memberof MemoryCache
1093
1093
  */
1094
- scard(key, callback) {
1095
- let retVal = 0;
1096
- if (this._hasKey(key)) {
1097
- this._testType(key, 'set', true, callback);
1098
- retVal = this._getKey(key).length;
1099
- }
1100
- return this._handleCallback(callback, retVal);
1094
+ _setField(key, field, value) {
1095
+ this._getKey(key)[field] = value;
1101
1096
  }
1102
1097
  /**
1103
1098
  *
1104
1099
  *
1105
- * @param {string} key
1106
- * @param {string} member
1100
+ * @private
1107
1101
  * @param {Function} [callback]
1102
+ * @param {(any)} [message]
1103
+ * @param {*} [error]
1104
+ * @param {boolean} [nolog]
1108
1105
  * @returns {*}
1109
1106
  * @memberof MemoryCache
1110
1107
  */
1111
- sismember(key, member, callback) {
1112
- let retVal = 0;
1113
- if (this._hasKey(key)) {
1114
- this._testType(key, 'set', true, callback);
1115
- const val = this._getKey(key);
1116
- if (val.includes(member)) {
1117
- retVal = 1;
1108
+ _handleCallback(callback, message, error, nolog) {
1109
+ let err = error;
1110
+ let msg = message;
1111
+ nolog = isNil(nolog) ? true : nolog;
1112
+ if (nolog) {
1113
+ err = this._logReturn(error);
1114
+ msg = this._logReturn(message);
1115
+ }
1116
+ if (typeof callback === 'function') {
1117
+ callback(err, msg);
1118
+ return;
1119
+ }
1120
+ if (err) {
1121
+ throw new Error(err);
1122
+ }
1123
+ return msg;
1124
+ }
1125
+ _logReturn(message) {
1126
+ if (!isUndefined(message)) {
1127
+ if (this.multiMode) {
1128
+ if (!isNil(this.responseMessages)) {
1129
+ this.responseMessages.push(message);
1130
+ if (message === messages.ok) {
1131
+ message = messages.queued;
1132
+ }
1133
+ }
1118
1134
  }
1135
+ return message;
1119
1136
  }
1120
- return this._handleCallback(callback, retVal);
1137
+ return;
1121
1138
  }
1122
1139
  /**
1123
1140
  *
1124
1141
  *
1125
- * @param {string} key
1126
- * @param {Function} [callback]
1142
+ * @private
1143
+ * @param {any[]} [params]
1127
1144
  * @returns {*}
1128
1145
  * @memberof MemoryCache
1129
1146
  */
1130
- smembers(key, callback) {
1131
- let retVal = [];
1132
- if (this._hasKey(key)) {
1133
- this._testType(key, 'set', true, callback);
1134
- retVal = this._getKey(key);
1147
+ _retrieveCallback(params) {
1148
+ if (Array.isArray(params) && params.length > 0 && typeof params[params.length - 1] === 'function') {
1149
+ return params.pop();
1135
1150
  }
1136
- return this._handleCallback(callback, retVal);
1151
+ return;
1152
+ }
1153
+ }
1154
+
1155
+ /*
1156
+ * @Description:
1157
+ * @Usage:
1158
+ * @Author: richen
1159
+ * @Date: 2021-06-29 19:07:57
1160
+ * @LastEditTime: 2023-02-18 23:52:47
1161
+ */
1162
+ class MemoryStore {
1163
+ /**
1164
+ * Creates an instance of MemoryStore.
1165
+ * @param {MemoryStoreOpt} options
1166
+ * @memberof MemoryStore
1167
+ */
1168
+ constructor(options) {
1169
+ this.options = options;
1170
+ this.client = null;
1137
1171
  }
1138
1172
  /**
1173
+ * getConnection
1139
1174
  *
1140
- *
1141
- * @param {string} key
1142
- * @param {number} [count]
1143
- * @param {Function} [callback]
1144
1175
  * @returns {*}
1145
- * @memberof MemoryCache
1176
+ * @memberof MemoryStore
1146
1177
  */
1147
- spop(key, count, callback) {
1148
- let retVal = null;
1149
- count = count || 1;
1150
- if (isNaN(count)) {
1151
- return this._handleCallback(callback, null, messages.noint);
1178
+ getConnection() {
1179
+ if (!this.pool) {
1180
+ this.pool = new MemoryCache({
1181
+ database: this.options.db
1182
+ });
1152
1183
  }
1153
- if (this._hasKey(key)) {
1154
- retVal = [];
1155
- this._testType(key, 'set', true, callback);
1156
- const val = this._getKey(key);
1157
- const length = val.length;
1158
- count = count > length ? length : count;
1159
- for (let itr = 0; itr < count; itr++) {
1160
- retVal.push(val.pop());
1161
- }
1184
+ if (!this.client) {
1185
+ this.client = this.pool.createClient();
1186
+ this.client.status = "ready";
1162
1187
  }
1163
- return this._handleCallback(callback, retVal);
1188
+ return this.client;
1164
1189
  }
1165
1190
  /**
1191
+ * close
1166
1192
  *
1193
+ * @returns {*} {Promise<void>}
1194
+ * @memberof MemoryStore
1195
+ */
1196
+ async close() {
1197
+ this.client.end();
1198
+ this.client = null;
1199
+ }
1200
+ /**
1201
+ * release
1167
1202
  *
1168
- * @param {string} key
1169
- * @param {...any[]} members
1170
- * @returns {*}
1171
- * @memberof MemoryCache
1203
+ * @param {*} conn
1204
+ * @returns {*} {Promise<void>}
1205
+ * @memberof MemoryStore
1172
1206
  */
1173
- srem(key, ...members) {
1174
- let retVal = 0;
1175
- const callback = this._retrieveCallback(members);
1176
- if (this._hasKey(key)) {
1177
- this._testType(key, 'set', true, callback);
1178
- const val = this._getKey(key);
1179
- for (const index in members) {
1180
- if (members.hasOwnProperty(index)) {
1181
- const member = members[index];
1182
- const idx = val.indexOf(member);
1183
- if (idx !== -1) {
1184
- val.splice(idx, 1);
1185
- retVal++;
1186
- }
1187
- }
1188
- }
1189
- this._setKey(key, val);
1190
- }
1191
- return this._handleCallback(callback, retVal);
1207
+ async release(conn) {
1208
+ return;
1192
1209
  }
1193
1210
  /**
1211
+ * defineCommand
1194
1212
  *
1213
+ * @param {string} name
1214
+ * @param {*} scripts
1215
+ * @memberof MemoryStore
1216
+ */
1217
+ async defineCommand(name, scripts) {
1218
+ throw new Error(messages.unsupported);
1219
+ }
1220
+ /**
1221
+ * get and compare value
1195
1222
  *
1196
- * @param {string} sourcekey
1197
- * @param {string} destkey
1198
- * @param {string} member
1199
- * @param {Function} [callback]
1200
- * @returns {*}
1201
- * @memberof MemoryCache
1223
+ * @param {string} name
1224
+ * @param {(string | number)} value
1225
+ * @returns {*} {Promise<any>}
1226
+ * @memberof MemoryStore
1202
1227
  */
1203
- smove(sourcekey, destkey, member, callback) {
1204
- let retVal = 0;
1205
- if (this._hasKey(sourcekey)) {
1206
- this._testType(sourcekey, 'set', true, callback);
1207
- const val = this._getKey(sourcekey);
1208
- const idx = val.indexOf(member);
1209
- if (idx !== -1) {
1210
- this.sadd(destkey, member);
1211
- val.splice(idx, 1);
1212
- retVal = 1;
1213
- }
1228
+ async getCompare(name, value) {
1229
+ const client = this.getConnection();
1230
+ const val = client.get(`${this.options.keyPrefix}${name}`);
1231
+ if (!val) {
1232
+ return 0;
1233
+ }
1234
+ else if (val == value) {
1235
+ return client.del(`${this.options.keyPrefix}${name}`);
1236
+ }
1237
+ else {
1238
+ return -1;
1214
1239
  }
1215
- return this._handleCallback(callback, retVal);
1216
1240
  }
1217
- // ---------------------------------------
1218
- // ## Transactions (Atomic) ##
1219
- // ---------------------------------------
1220
- // TODO: Transaction Queues watch and unwatch
1221
- // https://redis.io/topics/transactions
1222
- // This can be accomplished by temporarily swapping this.cache to a temporary copy of the current statement
1223
- // holding and then using __.merge on actual this.cache with the temp storage.
1224
- discard(callback, silent) {
1225
- // Clear the queue mode, drain the queue, empty the watch list
1226
- if (this.multiMode) {
1227
- this.cache = this.databases[this.currentDBIndex];
1228
- this.tempCache = {};
1229
- this.multiMode = false;
1230
- this.responseMessages = [];
1231
- }
1232
- else if (!silent) {
1233
- return this._handleCallback(callback, null, messages.nomultidiscard);
1234
- }
1235
- return this._handleCallback(callback, messages.ok);
1236
- }
1237
- // ---------------------------------------
1238
- // ## Internal - Key ##
1239
- // ---------------------------------------
1241
+ }
1242
+
1243
+ /*
1244
+ * @Author: richen
1245
+ * @Date: 2020-11-30 15:56:08
1246
+ * @LastEditors: Please set LastEditors
1247
+ * @LastEditTime: 2023-02-19 00:02:09
1248
+ * @License: BSD (3-Clause)
1249
+ * @Copyright (c) - <richenlin(at)gmail.com>
1250
+ */
1251
+ /**
1252
+ *
1253
+ *
1254
+ * @export
1255
+ * @class RedisStore
1256
+ */
1257
+ class RedisStore {
1240
1258
  /**
1241
- *
1242
- *
1243
- * @param {string} key
1244
- * @param {Function} [callback]
1245
- * @returns {*}
1246
- * @memberof MemoryCache
1259
+ * Creates an instance of RedisStore.
1260
+ * @param {RedisStoreOpt} options
1261
+ * @memberof RedisStore
1247
1262
  */
1248
- pttl(key, callback) {
1249
- let retVal = -2;
1250
- if (this._hasKey(key)) {
1251
- if (!isNil(this.cache[key].timeout)) {
1252
- retVal = this.cache[key].timeout - Date.now();
1253
- // Prevent unexpected errors if the actual ttl just happens to be -2 or -1
1254
- if (retVal < 0 && retVal > -3) {
1255
- retVal = -3;
1263
+ constructor(options) {
1264
+ this.options = this.parseOpt(options);
1265
+ this.pool = null;
1266
+ }
1267
+ // parseOpt
1268
+ parseOpt(options) {
1269
+ const opt = {
1270
+ type: options.type,
1271
+ host: options.host || '127.0.0.1',
1272
+ port: options.port || 3306,
1273
+ username: options.username || "",
1274
+ password: options.password || "",
1275
+ db: options.db || 0,
1276
+ timeout: options.timeout,
1277
+ keyPrefix: options.keyPrefix || '',
1278
+ poolSize: options.poolSize || 10,
1279
+ connectTimeout: options.connectTimeout || 500,
1280
+ };
1281
+ if (helper.isArray(options.host)) {
1282
+ const hosts = [];
1283
+ for (let i = 0; i < options.host.length; i++) {
1284
+ const h = options.host[i];
1285
+ if (!helper.isEmpty(options.host[i])) {
1286
+ let p;
1287
+ if (helper.isArray(options.port)) {
1288
+ p = options.port[i];
1289
+ }
1290
+ else {
1291
+ p = options.port || 6379;
1292
+ }
1293
+ hosts.push({
1294
+ host: h,
1295
+ port: helper.toNumber(p),
1296
+ });
1256
1297
  }
1257
1298
  }
1299
+ // sentinel
1300
+ if (!helper.isEmpty(options.name)) {
1301
+ opt.host = "";
1302
+ opt.port = null;
1303
+ opt.sentinels = [...hosts];
1304
+ opt.sentinelUsername = options.username;
1305
+ opt.sentinelPassword = options.password;
1306
+ }
1258
1307
  else {
1259
- retVal = -1;
1308
+ // cluster
1309
+ opt.host = "";
1310
+ opt.port = null;
1311
+ opt.clusters = [...hosts];
1260
1312
  }
1261
1313
  }
1262
- return this._handleCallback(callback, retVal);
1314
+ return opt;
1263
1315
  }
1264
1316
  /**
1317
+ * create connection by native
1265
1318
  *
1266
- *
1267
- * @private
1268
- * @param {string} key
1269
- * @param {Function} [callback]
1270
- * @returns {*}
1271
- * @memberof MemoryCache
1319
+ * @param {number} [connNum=0]
1320
+ * @returns {*} {Promise<Redis | Cluster>}
1321
+ * @memberof RedisStore
1272
1322
  */
1273
- persist(key, callback) {
1274
- let retVal = 0;
1275
- if (this._hasKey(key)) {
1276
- if (!isNil(this._key(key).timeout)) {
1277
- this._key(key).timeout = null;
1278
- retVal = 1;
1279
- }
1323
+ async connect(connNum = 0) {
1324
+ if (this.client && this.client.status === 'ready') {
1325
+ return this.client;
1280
1326
  }
1281
- return this._handleCallback(callback, retVal);
1282
- }
1283
- /**
1284
- *
1285
- *
1286
- * @private
1287
- * @param {string} key
1288
- * @returns {*} {boolean}
1289
- * @memberof MemoryCache
1290
- */
1291
- _hasKey(key) {
1292
- return this.cache.hasOwnProperty(key);
1327
+ const defer = helper.getDefer();
1328
+ let connection;
1329
+ if (!helper.isEmpty(this.options.clusters)) {
1330
+ connection = new Cluster([...this.options.clusters], { redisOptions: this.options });
1331
+ }
1332
+ else {
1333
+ connection = new Redis(this.options);
1334
+ }
1335
+ // 去除prefix, 防止重复
1336
+ this.options.keyPrefix = "";
1337
+ connection.on('end', () => {
1338
+ if (connNum < 3) {
1339
+ connNum++;
1340
+ defer.resolve(this.connect(connNum));
1341
+ }
1342
+ else {
1343
+ this.close();
1344
+ defer.reject('redis connection end');
1345
+ }
1346
+ });
1347
+ connection.on('ready', () => {
1348
+ this.client = connection;
1349
+ defer.resolve(connection);
1350
+ });
1351
+ return defer.promise;
1293
1352
  }
1294
1353
  /**
1354
+ * get connection from pool
1295
1355
  *
1296
- *
1297
- * @private
1298
- * @param {*} value
1299
- * @param {string} type
1300
- * @param {number} timeout
1301
1356
  * @returns {*}
1302
- * @memberof MemoryCache
1357
+ * @memberof RedisStore
1303
1358
  */
1304
- _makeKey(value, type, timeout) {
1305
- return { value: value, type: type, timeout: timeout || null, lastAccess: Date.now() };
1359
+ getConnection() {
1360
+ if (!this.pool || !this.pool.acquire) {
1361
+ const factory = {
1362
+ create: () => {
1363
+ return this.connect();
1364
+ },
1365
+ destroy: () => {
1366
+ return this.close();
1367
+ },
1368
+ validate: (resource) => {
1369
+ return Promise.resolve(resource.status === 'ready');
1370
+ }
1371
+ };
1372
+ this.pool = genericPool.createPool(factory, {
1373
+ max: this.options.poolSize || 10,
1374
+ min: 2 // minimum size of the pool
1375
+ });
1376
+ this.pool.on('factoryCreateError', function (err) {
1377
+ DefaultLogger.Error(err);
1378
+ });
1379
+ this.pool.on('factoryDestroyError', function (err) {
1380
+ DefaultLogger.Error(err);
1381
+ });
1382
+ }
1383
+ return this.pool.acquire();
1306
1384
  }
1307
1385
  /**
1386
+ * close connection
1308
1387
  *
1309
- *
1310
- * @private
1311
- * @param {string} key
1312
1388
  * @returns {*}
1313
- * @memberof MemoryCache
1389
+ * @memberof RedisStore
1314
1390
  */
1315
- _key(key) {
1316
- this.cache[key].lastAccess = Date.now();
1317
- return this.cache[key];
1391
+ async close() {
1392
+ this.client.disconnect();
1393
+ this.client = null;
1394
+ this.pool.destroy(this.client);
1395
+ this.pool = null;
1396
+ return;
1318
1397
  }
1319
1398
  /**
1320
1399
  *
1321
1400
  *
1322
- * @private
1323
- * @param {string} key
1324
- * @param {number} amount
1325
- * @param {Function} [callback]
1401
+ * @param {*} conn
1326
1402
  * @returns {*}
1327
- * @memberof MemoryCache
1403
+ * @memberof RedisStore
1328
1404
  */
1329
- _addToKey(key, amount, callback) {
1330
- let keyValue = 0;
1331
- if (isNaN(amount) || isNil(amount)) {
1332
- return this._handleCallback(callback, null, messages.noint);
1333
- }
1334
- if (this._hasKey(key)) {
1335
- this._testType(key, 'string', true, callback);
1336
- keyValue = parseInt(this._getKey(key));
1337
- if (isNaN(keyValue) || isNil(keyValue)) {
1338
- return this._handleCallback(callback, null, messages.noint);
1339
- }
1340
- }
1341
- else {
1342
- this.cache[key] = this._makeKey('0', 'string');
1405
+ async release(conn) {
1406
+ if (this.pool.isBorrowedResource(conn)) {
1407
+ return this.pool.release(conn);
1343
1408
  }
1344
- const val = keyValue + amount;
1345
- this._setKey(key, val.toString());
1346
- return val;
1409
+ return Promise.resolve();
1347
1410
  }
1348
1411
  /**
1412
+ * defineCommand
1349
1413
  *
1350
- *
1351
- * @private
1352
- * @param {string} key
1353
- * @param {string} type
1354
- * @param {boolean} [throwError]
1355
- * @param {Function} [callback]
1414
+ * @param {string} name
1415
+ * @param {{ numberOfKeys?: number; lua?: string; }} scripts
1356
1416
  * @returns {*}
1357
- * @memberof MemoryCache
1417
+ * @memberof RedisStore
1358
1418
  */
1359
- _testType(key, type, throwError, callback) {
1360
- throwError = !!throwError;
1361
- const keyType = this._key(key).type;
1362
- if (keyType !== type) {
1363
- if (throwError) {
1364
- return this._handleCallback(callback, null, messages.wrongTypeOp);
1365
- }
1366
- return false;
1419
+ async defineCommand(name, scripts) {
1420
+ const conn = await this.getConnection();
1421
+ if (!conn[name]) {
1422
+ conn.defineCommand(name, scripts);
1367
1423
  }
1368
- return true;
1424
+ return conn;
1369
1425
  }
1370
1426
  /**
1427
+ * get and compare value
1371
1428
  *
1372
- *
1373
- * @private
1374
- * @param {string} key
1375
- * @returns {*}
1376
- * @memberof MemoryCache
1429
+ * @param {string} name
1430
+ * @param {(string | number)} value
1431
+ * @returns {*} {Promise<any>}
1432
+ * @memberof RedisStore
1377
1433
  */
1378
- _getKey(key) {
1379
- const _key = this._key(key) || {};
1380
- if (_key.timeout && _key.timeout <= Date.now()) {
1381
- this.del(key);
1382
- return null;
1434
+ async getCompare(name, value) {
1435
+ let conn;
1436
+ try {
1437
+ conn = await this.defineCommand("getCompare", {
1438
+ numberOfKeys: 1,
1439
+ lua: `
1440
+ local remote_value = redis.call("get",KEYS[1])
1441
+
1442
+ if (not remote_value) then
1443
+ return 0
1444
+ elseif (remote_value == ARGV[1]) then
1445
+ return redis.call("del",KEYS[1])
1446
+ else
1447
+ return -1
1448
+ end
1449
+ `
1450
+ });
1451
+ return conn.getCompare(name, value);
1452
+ }
1453
+ catch (error) {
1454
+ throw error;
1455
+ }
1456
+ finally {
1457
+ this.release(conn);
1458
+ }
1459
+ }
1460
+ }
1461
+
1462
+ /*
1463
+ * @Description:
1464
+ * @Usage:
1465
+ * @Author: richen
1466
+ * @Date: 2021-12-02 15:26:55
1467
+ * @LastEditTime: 2023-02-19 01:03:59
1468
+ */
1469
+ const defaultOptions = {
1470
+ type: 'memory',
1471
+ host: '',
1472
+ port: 0,
1473
+ keyPrefix: 'Koatty',
1474
+ timeout: 600,
1475
+ poolSize: 10,
1476
+ connectTimeout: 500,
1477
+ db: 0
1478
+ };
1479
+ /**
1480
+ *
1481
+ *
1482
+ * @export
1483
+ * @class Store
1484
+ */
1485
+ class CacheStore {
1486
+ /**
1487
+ * Creates an instance of CacheStore.
1488
+ * @param {StoreOptions} options
1489
+ * @memberof CacheStore
1490
+ */
1491
+ constructor(options) {
1492
+ this.options = { ...defaultOptions, ...options };
1493
+ this.client = null;
1494
+ switch (options.type) {
1495
+ case "redis":
1496
+ this.client = new RedisStore(options);
1497
+ break;
1498
+ case "memory":
1499
+ default:
1500
+ this.client = new MemoryStore(options);
1501
+ break;
1383
1502
  }
1384
- return _key.value;
1385
1503
  }
1386
1504
  /**
1387
1505
  *
1388
1506
  *
1389
- * @private
1390
- * @param {string} key
1391
- * @param {(number | string)} value
1392
- * @memberof MemoryCache
1507
+ * @static
1508
+ * @returns
1393
1509
  */
1394
- _setKey(key, value) {
1395
- this.cache[key].value = value;
1396
- this.cache[key].lastAccess = Date.now();
1510
+ static getInstance(options) {
1511
+ if (this.instance) {
1512
+ return this.instance;
1513
+ }
1514
+ this.instance = new CacheStore(options);
1515
+ return this.instance;
1516
+ }
1517
+ getConnection() {
1518
+ return this.client.getConnection();
1519
+ }
1520
+ close() {
1521
+ return this.client.close();
1522
+ }
1523
+ release(conn) {
1524
+ return this.client.release(conn);
1525
+ }
1526
+ defineCommand(name, scripts) {
1527
+ return this.client.defineCommand(name, scripts);
1528
+ }
1529
+ getCompare(name, value) {
1530
+ return this.client.getCompare(name, value);
1397
1531
  }
1398
1532
  /**
1533
+ * handler for native client
1399
1534
  *
1400
- *
1401
- * @private
1402
- * @param {string} key
1403
- * @param {string} field
1404
- * @param {number} [amount]
1405
- * @param {boolean} [useFloat]
1406
- * @param {Function} [callback]
1535
+ * @param {string} name
1536
+ * @param {any[]} data
1407
1537
  * @returns {*}
1408
- * @memberof MemoryCache
1538
+ * @memberof RedisStore
1409
1539
  */
1410
- _addToField(key, field, amount, useFloat, callback) {
1411
- useFloat = useFloat || false;
1412
- let fieldValue = useFloat ? 0.0 : 0;
1413
- let value = 0;
1414
- if (isNaN(amount) || isNil(amount)) {
1415
- return this._handleCallback(callback, null, useFloat ? messages.nofloat : messages.noint);
1416
- }
1417
- if (this._hasKey(key)) {
1418
- this._testType(key, 'hash', true, callback);
1419
- if (this._hasField(key, field)) {
1420
- value = this._getField(key, field);
1421
- }
1540
+ async wrap(name, data) {
1541
+ let conn;
1542
+ try {
1543
+ conn = await this.getConnection();
1544
+ const res = await conn[name](...data);
1545
+ return res;
1422
1546
  }
1423
- else {
1424
- this.cache[key] = this._makeKey({}, 'hash');
1547
+ catch (err) {
1548
+ throw err;
1425
1549
  }
1426
- fieldValue = useFloat ? parseFloat(`${value}`) : parseInt(`${value}`);
1427
- amount = useFloat ? parseFloat(`${amount}`) : parseInt(`${amount}`);
1428
- if (isNaN(fieldValue) || isNil(fieldValue)) {
1429
- return this._handleCallback(callback, null, useFloat ? messages.nofloat : messages.noint);
1550
+ finally {
1551
+ this.release(conn);
1430
1552
  }
1431
- fieldValue += amount;
1432
- this._setField(key, field, fieldValue.toString());
1433
- return fieldValue;
1434
1553
  }
1435
1554
  /**
1436
- *
1437
- *
1438
- * @private
1439
- * @param {string} key
1440
- * @param {string} field
1441
- * @returns {*}
1442
- * @memberof MemoryCache
1555
+ * 字符串获取
1556
+ * @param name
1443
1557
  */
1444
- _getField(key, field) {
1445
- return this._getKey(key)[field];
1558
+ get(name) {
1559
+ return this.wrap('get', [`${this.options.keyPrefix || ""}${name}`]);
1446
1560
  }
1447
1561
  /**
1448
- *
1449
- *
1450
- * @private
1451
- * @param {string} key
1452
- * @param {string} field
1453
- * @returns {*} {boolean}
1454
- * @memberof MemoryCache
1562
+ * 字符串写入
1563
+ * @param name
1564
+ * @param value
1565
+ * @param timeout
1566
+ * @returns {Promise}
1455
1567
  */
1456
- _hasField(key, field) {
1457
- let retVal = false;
1458
- if (key && field) {
1459
- const ky = this._getKey(key);
1460
- if (ky) {
1461
- retVal = ky.hasOwnProperty(field);
1462
- }
1568
+ set(name, value, timeout) {
1569
+ if (typeof timeout !== 'number') {
1570
+ timeout = this.options.timeout;
1463
1571
  }
1464
- return retVal;
1572
+ return this.wrap('set', [`${this.options.keyPrefix || ""}${name}`, value, 'ex', timeout]);
1465
1573
  }
1466
1574
  /**
1467
- *
1468
- *
1469
- * @param {string} key
1470
- * @param {string} field
1471
- * @param {*} value
1472
- * @memberof MemoryCache
1575
+ * 以秒为单位,返回给定 key 的剩余生存时间
1576
+ * @param name
1577
+ * @returns {*}
1473
1578
  */
1474
- _setField(key, field, value) {
1475
- this._getKey(key)[field] = value;
1579
+ ttl(name) {
1580
+ return this.wrap('ttl', [`${this.options.keyPrefix || ""}${name}`]);
1476
1581
  }
1477
1582
  /**
1478
- *
1479
- *
1480
- * @private
1481
- * @param {Function} [callback]
1482
- * @param {(any)} [message]
1483
- * @param {*} [error]
1484
- * @param {boolean} [nolog]
1485
- * @returns {*}
1486
- * @memberof MemoryCache
1583
+ * 设置key超时属性
1584
+ * @param name
1585
+ * @param timeout
1487
1586
  */
1488
- _handleCallback(callback, message, error, nolog) {
1489
- let err = error;
1490
- let msg = message;
1491
- nolog = isNil(nolog) ? true : nolog;
1492
- if (nolog) {
1493
- err = this._logReturn(error);
1494
- msg = this._logReturn(message);
1495
- }
1496
- if (typeof callback === 'function') {
1497
- callback(err, msg);
1498
- return;
1499
- }
1500
- if (err) {
1501
- throw new Error(err);
1502
- }
1503
- return msg;
1587
+ expire(name, timeout) {
1588
+ return this.wrap('expire', [`${this.options.keyPrefix || ""}${name}`, timeout]);
1504
1589
  }
1505
- _logReturn(message) {
1506
- if (!isUndefined(message)) {
1507
- if (this.multiMode) {
1508
- if (!isNil(this.responseMessages)) {
1509
- this.responseMessages.push(message);
1510
- if (message === messages.ok) {
1511
- message = messages.queued;
1512
- }
1513
- }
1514
- }
1515
- return message;
1516
- }
1517
- return;
1590
+ /**
1591
+ * 删除key
1592
+ * @param name
1593
+ */
1594
+ rm(name) {
1595
+ return this.wrap('del', [`${this.options.keyPrefix || ""}${name}`]);
1518
1596
  }
1519
1597
  /**
1520
1598
  *
1521
1599
  *
1522
- * @private
1523
- * @param {any[]} [params]
1524
- * @returns {*}
1525
- * @memberof MemoryCache
1600
+ * @param {*} name
1601
+ * @returns
1526
1602
  */
1527
- _retrieveCallback(params) {
1528
- if (Array.isArray(params) && params.length > 0 && typeof params[params.length - 1] === 'function') {
1529
- return params.pop();
1530
- }
1531
- return;
1603
+ del(name) {
1604
+ return this.wrap('del', [`${this.options.keyPrefix || ""}${name}`]);
1532
1605
  }
1533
- }
1534
-
1535
- // const MemoryCache = require('@outofsync/memory-cache');
1536
- /*
1537
- * @Description:
1538
- * @Usage:
1539
- * @Author: richen
1540
- * @Date: 2021-06-29 19:07:57
1541
- * @LastEditTime: 2023-01-13 11:25:19
1542
- */
1543
- class MemoryStore extends CacheStore {
1544
1606
  /**
1545
- * Creates an instance of MemoryStore.
1546
- * @param {StoreOptions} options
1547
- * @memberof MemoryStore
1607
+ * 判断key是否存在
1608
+ * @param name
1548
1609
  */
1549
- constructor(options) {
1550
- super(options);
1551
- this.options = options;
1552
- this.client = null;
1610
+ exists(name) {
1611
+ return this.wrap('exists', [`${this.options.keyPrefix || ""}${name}`]);
1553
1612
  }
1554
1613
  /**
1555
- * getConnection
1556
- *
1614
+ * 自增
1615
+ * @param name
1616
+ */
1617
+ incr(name) {
1618
+ return this.wrap('incr', [`${this.options.keyPrefix || ""}${name}`]);
1619
+ }
1620
+ /**
1621
+ * 自减
1622
+ * @param name
1557
1623
  * @returns {*}
1558
- * @memberof MemoryStore
1559
1624
  */
1560
- getConnection() {
1561
- if (!this.pool) {
1562
- this.pool = new MemoryCache({
1563
- database: this.options.db
1564
- });
1565
- }
1566
- if (!this.client) {
1567
- this.client = this.pool.createClient();
1568
- this.client.status = "ready";
1569
- }
1570
- return this.client;
1571
- }
1572
- /**
1573
- * close
1574
- *
1575
- * @returns {*} {Promise<void>}
1576
- * @memberof MemoryStore
1577
- */
1578
- async close() {
1579
- this.client.end();
1580
- this.client = null;
1625
+ decr(name) {
1626
+ return this.wrap('decr', [`${this.options.keyPrefix || ""}${name}`]);
1581
1627
  }
1582
1628
  /**
1583
- * release
1584
- *
1585
- * @param {*} conn
1586
- * @returns {*} {Promise<void>}
1587
- * @memberof MemoryStore
1629
+ * 将 key 所储存的值增加增量
1630
+ * @param name
1631
+ * @param incr
1632
+ * @returns {*}
1588
1633
  */
1589
- async release(conn) {
1590
- return;
1634
+ incrby(name, incr = 1) {
1635
+ return this.wrap('incrby', [`${this.options.keyPrefix || ""}${name}`, incr]);
1591
1636
  }
1592
1637
  /**
1593
- * defineCommand
1638
+ * 将 key 所储存的值减去减量
1594
1639
  *
1595
- * @param {string} name
1596
- * @param {*} scripts
1597
- * @memberof MemoryStore
1640
+ * @param {any} name
1641
+ * @param {any} decr
1598
1642
  */
1599
- async defineCommand(name, scripts) {
1600
- throw new Error(messages.unsupported);
1643
+ decrby(name, decr = 1) {
1644
+ return this.wrap('decrby', [`${this.options.keyPrefix || ""}${name}`, decr]);
1601
1645
  }
1602
1646
  /**
1603
- * get and compare value
1604
- *
1605
- * @param {string} name
1606
- * @param {(string | number)} value
1607
- * @returns {*} {Promise<any>}
1608
- * @memberof MemoryStore
1647
+ * 哈希写入
1648
+ * @param name
1649
+ * @param key
1650
+ * @param value
1651
+ * @param timeout
1609
1652
  */
1610
- async getCompare(name, value) {
1611
- const client = this.getConnection();
1612
- const val = client.get(`${this.options.keyPrefix}${name}`);
1613
- if (!val) {
1614
- return 0;
1615
- }
1616
- else if (val == value) {
1617
- return client.del(`${this.options.keyPrefix}${name}`);
1618
- }
1619
- else {
1620
- return -1;
1653
+ hset(name, key, value, timeout) {
1654
+ const setP = [this.wrap('hset', [`${this.options.keyPrefix || ""}${name}`, key, value])];
1655
+ if (typeof timeout !== 'number') {
1656
+ timeout = this.options.timeout;
1621
1657
  }
1658
+ setP.push(this.set(`${name}:${key}_ex`, 1, timeout));
1659
+ return Promise.all(setP);
1622
1660
  }
1623
- }
1624
-
1625
- /*
1626
- * @Author: richen
1627
- * @Date: 2020-11-30 15:56:08
1628
- * @LastEditors: Please set LastEditors
1629
- * @LastEditTime: 2021-12-02 15:30:11
1630
- * @License: BSD (3-Clause)
1631
- * @Copyright (c) - <richenlin(at)gmail.com>
1632
- */
1633
- /**
1634
- *
1635
- *
1636
- * @export
1637
- * @class RedisStore
1638
- */
1639
- class RedisStore extends CacheStore {
1640
1661
  /**
1641
- * Creates an instance of RedisStore.
1642
- * @param {StoreOptions} options
1643
- * @memberof RedisStore
1662
+ * 哈希获取
1663
+ * @param name
1664
+ * @param key
1665
+ * @returns {*}
1644
1666
  */
1645
- constructor(options) {
1646
- super(options);
1647
- this.options = this.parseOpt(options);
1648
- this.pool = null;
1649
- this.client = null;
1650
- }
1651
- // parseOpt
1652
- parseOpt(options) {
1653
- const opt = {
1654
- host: options.host || '127.0.0.1',
1655
- port: options.port || 3306,
1656
- username: options.username || "",
1657
- password: options.password || "",
1658
- db: options.db || 0,
1659
- timeout: options.timeout,
1660
- keyPrefix: options.keyPrefix || '',
1661
- poolSize: options.poolSize || 10,
1662
- connectTimeout: options.connectTimeout || 500,
1663
- };
1664
- if (helper.isArray(options.host)) {
1665
- const hosts = [];
1666
- for (let i = 0; i < options.host.length; i++) {
1667
- const h = options.host[i];
1668
- if (!helper.isEmpty(options.host[i])) {
1669
- let p;
1670
- if (helper.isArray(options.port)) {
1671
- p = options.port[i];
1672
- }
1673
- else {
1674
- p = options.port || 6379;
1675
- }
1676
- hosts.push({
1677
- host: h,
1678
- port: helper.toNumber(p),
1679
- });
1680
- }
1681
- }
1682
- // sentinel
1683
- if (!helper.isEmpty(options.name)) {
1684
- opt.host = "";
1685
- opt.port = null;
1686
- opt.sentinels = [...hosts];
1687
- opt.sentinelUsername = options.username;
1688
- opt.sentinelPassword = options.password;
1689
- }
1690
- else {
1691
- // cluster
1692
- opt.host = "";
1693
- opt.port = null;
1694
- opt.clusters = [...hosts];
1667
+ hget(name, key) {
1668
+ const setP = [this.get(`${name}:${key}_ex`)];
1669
+ setP.push(this.wrap('hget', [`${this.options.keyPrefix || ""}${name}`, key]));
1670
+ return Promise.all(setP).then(dataArr => {
1671
+ if (dataArr[0] === null) {
1672
+ this.hdel(name, key);
1673
+ return null;
1695
1674
  }
1696
- }
1697
- return opt;
1675
+ return dataArr[1] || null;
1676
+ });
1698
1677
  }
1699
1678
  /**
1700
- * create connection by native
1701
- *
1702
- * @param {number} [connNum=0]
1703
- * @returns {*} {Promise<IORedis.Redis | IORedis.Cluster>}
1704
- * @memberof RedisStore
1679
+ * 查看哈希表 hashKey 中,给定域 key 是否存在
1680
+ * @param name
1681
+ * @param key
1682
+ * @returns {*}
1705
1683
  */
1706
- async connect(connNum = 0) {
1707
- if (this.client && this.client.status === 'ready') {
1708
- return this.client;
1709
- }
1710
- const defer = helper.getDefer();
1711
- let connection;
1712
- if (!helper.isEmpty(this.options.clusters)) {
1713
- connection = new IORedis.Cluster([...this.options.clusters], { redisOptions: this.options });
1714
- }
1715
- else {
1716
- connection = new IORedis(this.options);
1717
- }
1718
- connection.on('end', () => {
1719
- if (connNum < 3) {
1720
- connNum++;
1721
- defer.resolve(this.connect(connNum));
1722
- }
1723
- else {
1724
- this.close();
1725
- defer.reject('redis connection end');
1684
+ hexists(name, key) {
1685
+ const setP = [this.get(`${name}:${key}_ex`)];
1686
+ setP.push(this.wrap('hexists', [`${this.options.keyPrefix || ""}${name}`, key]));
1687
+ return Promise.all(setP).then(dataArr => {
1688
+ if (dataArr[0] === null) {
1689
+ this.hdel(name, key);
1690
+ return 0;
1726
1691
  }
1692
+ return dataArr[1] || 0;
1727
1693
  });
1728
- connection.on('ready', () => {
1729
- this.client = connection;
1730
- defer.resolve(connection);
1731
- });
1732
- return defer.promise;
1733
1694
  }
1734
1695
  /**
1735
- * get connection from pool
1736
- *
1696
+ * 哈希删除
1697
+ * @param name
1698
+ * @param key
1737
1699
  * @returns {*}
1738
- * @memberof RedisStore
1739
1700
  */
1740
- getConnection() {
1741
- if (!this.pool || !this.pool.acquire) {
1742
- const factory = {
1743
- create: () => {
1744
- return this.connect();
1745
- },
1746
- destroy: () => {
1747
- return this.close();
1748
- },
1749
- validate: (resource) => {
1750
- return Promise.resolve(resource.status === 'ready');
1751
- }
1752
- };
1753
- this.pool = genericPool.createPool(factory, {
1754
- max: this.options.poolSize || 10,
1755
- min: 2 // minimum size of the pool
1756
- });
1757
- this.pool.on('factoryCreateError', function (err) {
1758
- DefaultLogger.Error(err);
1759
- });
1760
- this.pool.on('factoryDestroyError', function (err) {
1761
- DefaultLogger.Error(err);
1762
- });
1763
- }
1764
- return this.pool.acquire();
1701
+ hdel(name, key) {
1702
+ const setP = [this.del(`${name}:${key}_ex`)];
1703
+ setP.push(this.wrap('hdel', [`${this.options.keyPrefix || ""}${name}`, key]));
1704
+ return Promise.all(setP);
1765
1705
  }
1766
1706
  /**
1767
- * close connection
1768
- *
1707
+ * 返回哈希表 key 中域的数量
1708
+ * @param name
1769
1709
  * @returns {*}
1770
- * @memberof RedisStore
1771
1710
  */
1772
- async close() {
1773
- this.client.disconnect();
1774
- this.client = null;
1775
- this.pool.destroy(this.client);
1776
- this.pool = null;
1777
- return;
1711
+ hlen(name) {
1712
+ return this.wrap('hlen', [`${this.options.keyPrefix || ""}${name}`]);
1778
1713
  }
1779
1714
  /**
1780
- *
1781
- *
1782
- * @param {*} conn
1715
+ * 给哈希表指定key,增加increment
1716
+ * @param name
1717
+ * @param key
1718
+ * @param incr
1783
1719
  * @returns {*}
1784
- * @memberof RedisStore
1785
1720
  */
1786
- async release(conn) {
1787
- if (this.pool.isBorrowedResource(conn)) {
1788
- return this.pool.release(conn);
1789
- }
1790
- return Promise.resolve();
1721
+ hincrby(name, key, incr = 1) {
1722
+ return this.wrap('hincrby', [`${this.options.keyPrefix || ""}${name}`, key, incr]);
1791
1723
  }
1792
1724
  /**
1793
- * defineCommand
1794
- *
1795
- * @param {string} name
1796
- * @param {{ numberOfKeys?: number; lua?: string; }} scripts
1725
+ * 返回哈希表所有key-value
1726
+ * @param name
1797
1727
  * @returns {*}
1798
- * @memberof RedisStore
1799
1728
  */
1800
- async defineCommand(name, scripts) {
1801
- const conn = await this.getConnection();
1802
- if (!conn[name]) {
1803
- conn.defineCommand(name, scripts);
1804
- }
1805
- return conn;
1729
+ hgetall(name) {
1730
+ return this.wrap('hgetall', [`${this.options.keyPrefix || ""}${name}`]);
1731
+ }
1732
+ /**
1733
+ * 返回哈希表所有key
1734
+ * @param name
1735
+ * @returns {*}
1736
+ */
1737
+ hkeys(name) {
1738
+ return this.wrap('hkeys', [`${this.options.keyPrefix || ""}${name}`]);
1739
+ }
1740
+ /**
1741
+ * 返回哈希表所有value
1742
+ * @param name
1743
+ * @returns {*}
1744
+ */
1745
+ hvals(name) {
1746
+ return this.wrap('hvals', [`${this.options.keyPrefix || ""}${name}`]);
1747
+ }
1748
+ /**
1749
+ * 判断列表长度,若不存在则表示为空
1750
+ * @param name
1751
+ * @returns {*}
1752
+ */
1753
+ llen(name) {
1754
+ return this.wrap('llen', [`${this.options.keyPrefix || ""}${name}`]);
1755
+ }
1756
+ /**
1757
+ * 将值插入列表表尾
1758
+ * @param name
1759
+ * @param value
1760
+ * @returns {*}
1761
+ */
1762
+ rpush(name, value) {
1763
+ return this.wrap('rpush', [`${this.options.keyPrefix || ""}${name}`, value]);
1806
1764
  }
1807
1765
  /**
1808
- * get and compare value
1766
+ *
1809
1767
  *
1810
1768
  * @param {string} name
1811
1769
  * @param {(string | number)} value
1812
- * @returns {*} {Promise<any>}
1770
+ * @returns {*}
1813
1771
  * @memberof RedisStore
1814
1772
  */
1815
- async getCompare(name, value) {
1816
- let conn;
1817
- try {
1818
- conn = await this.defineCommand("getCompare", {
1819
- numberOfKeys: 1,
1820
- lua: `
1821
- local remote_value = redis.call("get",KEYS[1])
1822
-
1823
- if (not remote_value) then
1824
- return 0
1825
- elseif (remote_value == ARGV[1]) then
1826
- return redis.call("del",KEYS[1])
1827
- else
1828
- return -1
1829
- end
1830
- `
1831
- });
1832
- return conn.getCompare(name, value);
1833
- }
1834
- catch (error) {
1835
- throw error;
1836
- }
1837
- finally {
1838
- this.release(conn);
1839
- }
1773
+ lpush(name, value) {
1774
+ return this.wrap('lpush', [`${this.options.keyPrefix || ""}${name}`, value]);
1775
+ }
1776
+ /**
1777
+ * 将列表表头取出,并去除
1778
+ * @param name
1779
+ * @returns {*}
1780
+ */
1781
+ lpop(name) {
1782
+ return this.wrap('lpop', [`${this.options.keyPrefix || ""}${name}`]);
1840
1783
  }
1841
- }
1842
-
1843
- /**
1844
- *
1845
- *
1846
- * @export
1847
- * @class Store
1848
- */
1849
- class Store {
1850
1784
  /**
1851
1785
  *
1852
1786
  *
1853
- * @static
1854
- * @returns
1855
- * @memberof ValidateUtil
1787
+ * @param {string} name
1788
+ * @returns {*}
1789
+ * @memberof RedisStore
1856
1790
  */
1857
- static getInstance(options) {
1858
- if (this.instance) {
1859
- return this.instance;
1860
- }
1861
- options = {
1862
- ...{
1863
- type: 'memory',
1864
- host: '',
1865
- port: 0,
1866
- keyPrefix: 'Koatty',
1867
- timeout: 600,
1868
- poolSize: 10,
1869
- connectTimeout: 500,
1870
- db: 0
1871
- }, ...options
1872
- };
1873
- switch (options.type) {
1874
- case "redis":
1875
- this.instance = new RedisStore(options);
1876
- break;
1877
- case "memory":
1878
- default:
1879
- this.instance = new MemoryStore(options);
1880
- break;
1791
+ rpop(name) {
1792
+ return this.wrap('rpop', [`${this.options.keyPrefix || ""}${name}`]);
1793
+ }
1794
+ /**
1795
+ * 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定
1796
+ * @param name
1797
+ * @param start
1798
+ * @param stop
1799
+ * @returns {*}
1800
+ */
1801
+ lrange(name, start, stop) {
1802
+ return this.wrap('lrange', [`${this.options.keyPrefix || ""}${name}`, start, stop]);
1803
+ }
1804
+ /**
1805
+ * 集合新增
1806
+ * @param name
1807
+ * @param value
1808
+ * @param timeout
1809
+ * @returns {*}
1810
+ */
1811
+ sadd(name, value, timeout) {
1812
+ const setP = [this.wrap('sadd', [`${this.options.keyPrefix || ""}${name}`, value])];
1813
+ if (typeof timeout !== 'number') {
1814
+ setP.push(this.wrap('expire', [`${this.options.keyPrefix || ""}${name}`, timeout]));
1881
1815
  }
1882
- return this.instance;
1816
+ return Promise.all(setP);
1817
+ }
1818
+ /**
1819
+ * 返回集合的基数(集合中元素的数量)
1820
+ * @param name
1821
+ * @returns {*}
1822
+ */
1823
+ scard(name) {
1824
+ return this.wrap('scard', [`${this.options.keyPrefix || ""}${name}`]);
1825
+ }
1826
+ /**
1827
+ * 判断 member 元素是否集合的成员
1828
+ * @param name
1829
+ * @param key
1830
+ * @returns {*}
1831
+ */
1832
+ sismember(name, key) {
1833
+ return this.wrap('sismember', [`${this.options.keyPrefix || ""}${name}`, key]);
1834
+ }
1835
+ /**
1836
+ * 返回集合中的所有成员
1837
+ * @param name
1838
+ * @returns {*}
1839
+ */
1840
+ smembers(name) {
1841
+ return this.wrap('smembers', [`${this.options.keyPrefix || ""}${name}`]);
1842
+ }
1843
+ /**
1844
+ * 移除并返回集合中的一个随机元素
1845
+ * @param name
1846
+ * @returns {*}
1847
+ */
1848
+ spop(name) {
1849
+ return this.wrap('spop', [`${this.options.keyPrefix || ""}${name}`]);
1850
+ }
1851
+ /**
1852
+ * 移除集合 key 中的一个 member 元素
1853
+ * @param name
1854
+ * @param key
1855
+ * @returns {*}
1856
+ */
1857
+ srem(name, key) {
1858
+ return this.wrap('srem', [`${this.options.keyPrefix || ""}${name}`, key]);
1859
+ }
1860
+ /**
1861
+ * 将 member 元素从 source 集合移动到 destination 集合
1862
+ * @param source
1863
+ * @param destination
1864
+ * @param member
1865
+ * @returns {*}
1866
+ */
1867
+ smove(source, destination, member) {
1868
+ return this.wrap('smove', [`${this.options.keyPrefix || ""}${source}`, `${this.options.keyPrefix}${destination}`, member]);
1883
1869
  }
1884
1870
  }
1885
1871
 
1886
- export { CacheStore, MemoryStore, Store };
1872
+ export { CacheStore };