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