koatty_store 1.5.4 → 1.5.6

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,54 +1,1916 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Store = exports.CacheStore = exports.MemoryStore = void 0;
4
- const memory_1 = require("./store/memory");
5
- const redis_1 = require("./store/redis");
6
- var memory_2 = require("./store/memory");
7
- Object.defineProperty(exports, "MemoryStore", { enumerable: true, get: function () { return memory_2.MemoryStore; } });
8
- // export
9
- var store_1 = require("./store");
10
- Object.defineProperty(exports, "CacheStore", { enumerable: true, get: function () { return store_1.CacheStore; } });
11
- /**
12
- *
13
- *
14
- * @export
15
- * @class Store
16
- */
17
- class Store {
18
- /**
19
- *
20
- *
21
- * @static
22
- * @returns
23
- * @memberof ValidateUtil
24
- */
25
- static getInstance(options) {
26
- if (this.instance) {
27
- return this.instance;
28
- }
29
- options = {
30
- ...{
31
- type: 'memory',
32
- host: '',
33
- port: 0,
34
- keyPrefix: 'Koatty',
35
- timeout: 600,
36
- poolSize: 10,
37
- connectTimeout: 500,
38
- db: 0
39
- }, ...options
40
- };
41
- switch (options.type) {
42
- case "redis":
43
- this.instance = new redis_1.RedisStore(options);
44
- break;
45
- case "memory":
46
- default:
47
- this.instance = new memory_1.MemoryStore(options);
48
- break;
49
- }
50
- return this.instance;
1
+ /*!
2
+ * @Author: richen
3
+ * @Date: 2022-11-03 16:31:15
4
+ * @License: BSD (3-Clause)
5
+ * @Copyright (c) - <richenlin(at)gmail.com>
6
+ * @HomePage: https://koatty.org/
7
+ */
8
+ 'use strict';
9
+
10
+ Object.defineProperty(exports, '__esModule', { value: true });
11
+
12
+ var lodash = require('lodash');
13
+ var helper = require('koatty_lib');
14
+ var events = require('events');
15
+ var koatty_logger = require('koatty_logger');
16
+ var IORedis = require('ioredis');
17
+ var genericPool = require('generic-pool');
18
+
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
+ }
33
+ });
51
34
  }
35
+ n["default"] = e;
36
+ return Object.freeze(n);
52
37
  }
38
+
39
+ var helper__namespace = /*#__PURE__*/_interopNamespace(helper);
40
+ var IORedis__default = /*#__PURE__*/_interopDefaultLegacy(IORedis);
41
+ var genericPool__default = /*#__PURE__*/_interopDefaultLegacy(genericPool);
42
+
43
+ /*
44
+ * @Description:
45
+ * @Usage:
46
+ * @Author: richen
47
+ * @Date: 2021-12-02 15:26:55
48
+ * @LastEditTime: 2021-12-02 15:33:22
49
+ */
50
+ /**
51
+ *
52
+ *
53
+ * @export
54
+ * @class Store
55
+ */
56
+ class CacheStore {
57
+ /**
58
+ * Creates an instance of CacheStore.
59
+ * @param {StoreOptions} options
60
+ * @memberof CacheStore
61
+ */
62
+ 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.");
81
+ }
82
+ /**
83
+ * handler for native client
84
+ *
85
+ * @param {string} name
86
+ * @param {any[]} data
87
+ * @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}
117
+ */
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]);
123
+ }
124
+ /**
125
+ * 以秒为单位,返回给定 key 的剩余生存时间
126
+ * @param name
127
+ * @returns {*}
128
+ */
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}`]);
146
+ }
147
+ /**
148
+ *
149
+ *
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
166
+ */
167
+ incr(name) {
168
+ return this.wrap('incr', [`${this.options.keyPrefix}${name}`]);
169
+ }
170
+ /**
171
+ * 自减
172
+ * @param name
173
+ * @returns {*}
174
+ */
175
+ decr(name) {
176
+ return this.wrap('decr', [`${this.options.keyPrefix}${name}`]);
177
+ }
178
+ /**
179
+ * 将 key 所储存的值增加增量
180
+ * @param name
181
+ * @param incr
182
+ * @returns {*}
183
+ */
184
+ incrby(name, incr = 1) {
185
+ return this.wrap('incrby', [`${this.options.keyPrefix}${name}`, incr]);
186
+ }
187
+ /**
188
+ * 将 key 所储存的值减去减量
189
+ *
190
+ * @param {any} name
191
+ * @param {any} decr
192
+ */
193
+ decrby(name, decr = 1) {
194
+ return this.wrap('decrby', [`${this.options.keyPrefix}${name}`, decr]);
195
+ }
196
+ /**
197
+ * 哈希写入
198
+ * @param name
199
+ * @param key
200
+ * @param value
201
+ * @param timeout
202
+ */
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;
207
+ }
208
+ setP.push(this.set(`${name}:${key}_ex`, 1, timeout));
209
+ return Promise.all(setP);
210
+ }
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
+ });
227
+ }
228
+ /**
229
+ * 查看哈希表 hashKey 中,给定域 key 是否存在
230
+ * @param name
231
+ * @param key
232
+ * @returns {*}
233
+ */
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);
255
+ }
256
+ /**
257
+ * 返回哈希表 key 中域的数量
258
+ * @param name
259
+ * @returns {*}
260
+ */
261
+ hlen(name) {
262
+ return this.wrap('hlen', [`${this.options.keyPrefix}${name}`]);
263
+ }
264
+ /**
265
+ * 给哈希表指定key,增加increment
266
+ * @param name
267
+ * @param key
268
+ * @param incr
269
+ * @returns {*}
270
+ */
271
+ hincrby(name, key, incr = 1) {
272
+ return this.wrap('hincrby', [`${this.options.keyPrefix}${name}`, key, incr]);
273
+ }
274
+ /**
275
+ * 返回哈希表所有key-value
276
+ * @param name
277
+ * @returns {*}
278
+ */
279
+ hgetall(name) {
280
+ return this.wrap('hgetall', [`${this.options.keyPrefix}${name}`]);
281
+ }
282
+ /**
283
+ * 返回哈希表所有key
284
+ * @param name
285
+ * @returns {*}
286
+ */
287
+ hkeys(name) {
288
+ return this.wrap('hkeys', [`${this.options.keyPrefix}${name}`]);
289
+ }
290
+ /**
291
+ * 返回哈希表所有value
292
+ * @param name
293
+ * @returns {*}
294
+ */
295
+ hvals(name) {
296
+ return this.wrap('hvals', [`${this.options.keyPrefix}${name}`]);
297
+ }
298
+ /**
299
+ * 判断列表长度,若不存在则表示为空
300
+ * @param name
301
+ * @returns {*}
302
+ */
303
+ llen(name) {
304
+ return this.wrap('llen', [`${this.options.keyPrefix}${name}`]);
305
+ }
306
+ /**
307
+ * 将值插入列表表尾
308
+ * @param name
309
+ * @param value
310
+ * @returns {*}
311
+ */
312
+ rpush(name, value) {
313
+ return this.wrap('rpush', [`${this.options.keyPrefix}${name}`, value]);
314
+ }
315
+ /**
316
+ *
317
+ *
318
+ * @param {string} name
319
+ * @param {(string | number)} value
320
+ * @returns {*}
321
+ * @memberof RedisStore
322
+ */
323
+ lpush(name, value) {
324
+ return this.wrap('lpush', [`${this.options.keyPrefix}${name}`, value]);
325
+ }
326
+ /**
327
+ * 将列表表头取出,并去除
328
+ * @param name
329
+ * @returns {*}
330
+ */
331
+ lpop(name) {
332
+ return this.wrap('lpop', [`${this.options.keyPrefix}${name}`]);
333
+ }
334
+ /**
335
+ *
336
+ *
337
+ * @param {string} name
338
+ * @returns {*}
339
+ * @memberof RedisStore
340
+ */
341
+ rpop(name) {
342
+ return this.wrap('rpop', [`${this.options.keyPrefix}${name}`]);
343
+ }
344
+ /**
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
359
+ * @returns {*}
360
+ */
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]));
365
+ }
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}`]);
392
+ }
393
+ /**
394
+ * 移除并返回集合中的一个随机元素
395
+ * @param name
396
+ * @returns {*}
397
+ */
398
+ spop(name) {
399
+ return this.wrap('spop', [`${this.options.keyPrefix}${name}`]);
400
+ }
401
+ /**
402
+ * 移除集合 key 中的一个 member 元素
403
+ * @param name
404
+ * @param key
405
+ * @returns {*}
406
+ */
407
+ srem(name, key) {
408
+ return this.wrap('srem', [`${this.options.keyPrefix}${name}`, key]);
409
+ }
410
+ /**
411
+ * 将 member 元素从 source 集合移动到 destination 集合
412
+ * @param source
413
+ * @param destination
414
+ * @param member
415
+ * @returns {*}
416
+ */
417
+ smove(source, destination, member) {
418
+ return this.wrap('smove', [`${this.options.keyPrefix}${source}`, `${this.options.keyPrefix}${destination}`, member]);
419
+ }
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
+ /**
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;
472
+ }
473
+ /**
474
+ *
475
+ *
476
+ * @returns {*}
477
+ * @memberof MemoryCache
478
+ */
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;
488
+ }
489
+ /**
490
+ *
491
+ *
492
+ * @returns {*}
493
+ * @memberof MemoryCache
494
+ */
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;
501
+ }
502
+ /**
503
+ *
504
+ *
505
+ * @returns {*}
506
+ * @memberof MemoryCache
507
+ */
508
+ end() {
509
+ return this.quit();
510
+ }
511
+ /**
512
+ *
513
+ *
514
+ * @param {string} message
515
+ * @param {Function} [callback]
516
+ * @returns {*}
517
+ * @memberof MemoryCache
518
+ */
519
+ echo(message, callback) {
520
+ return this._handleCallback(callback, message);
521
+ }
522
+ /**
523
+ *
524
+ *
525
+ * @param {string} message
526
+ * @param {Function} [callback]
527
+ * @returns {*}
528
+ * @memberof MemoryCache
529
+ */
530
+ ping(message, callback) {
531
+ message = message || messages.pong;
532
+ return this._handleCallback(callback, message);
533
+ }
534
+ /**
535
+ *
536
+ *
537
+ * @param {string} password
538
+ * @param {Function} [callback]
539
+ * @returns {*}
540
+ * @memberof MemoryCache
541
+ */
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) {
569
+ let retVal = null;
570
+ if (this._hasKey(key)) {
571
+ this._testType(key, 'string', true, callback);
572
+ retVal = this._getKey(key);
573
+ }
574
+ return this._handleCallback(callback, retVal);
575
+ }
576
+ /**
577
+ * set(key, value, ttl, pttl, notexist, onlyexist, callback)
578
+ *
579
+ * @param {string} key
580
+ * @param {(string | number)} value
581
+ * @param {...any[]} params
582
+ * @returns {*}
583
+ * @memberof MemoryCache
584
+ */
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
+ }
632
+ if (this._hasKey(key)) {
633
+ this._testType(key, 'string', true, callback);
634
+ if (notexist) {
635
+ return this._handleCallback(callback, retVal);
636
+ }
637
+ }
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);
643
+ }
644
+ /**
645
+ *
646
+ *
647
+ * @param {string} key
648
+ * @param {Function} [callback]
649
+ * @returns {*}
650
+ * @memberof MemoryCache
651
+ */
652
+ ttl(key, callback) {
653
+ let retVal = this.pttl(key);
654
+ if (retVal >= 0 || retVal <= -3) {
655
+ retVal = Math.floor(retVal / 1000);
656
+ }
657
+ return this._handleCallback(callback, retVal);
658
+ }
659
+ /**
660
+ *
661
+ *
662
+ * @param {string} key
663
+ * @param {number} seconds
664
+ * @param {Function} [callback]
665
+ * @returns {*}
666
+ * @memberof MemoryCache
667
+ */
668
+ expire(key, seconds, callback) {
669
+ let retVal = 0;
670
+ if (this._hasKey(key)) {
671
+ this.cache[key].timeout = Date.now() + seconds * 1000;
672
+ retVal = 1;
673
+ }
674
+ return this._handleCallback(callback, retVal);
675
+ }
676
+ /**
677
+ *
678
+ *
679
+ * @param {...any[]} keys
680
+ * @returns {*}
681
+ * @memberof MemoryCache
682
+ */
683
+ del(...keys) {
684
+ 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++;
693
+ }
694
+ }
695
+ return this._handleCallback(callback, retVal);
696
+ }
697
+ /**
698
+ *
699
+ *
700
+ * @param {...any[]} keys
701
+ * @returns {*}
702
+ * @memberof MemoryCache
703
+ */
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
+ }
712
+ }
713
+ return this._handleCallback(callback, retVal);
714
+ }
715
+ /**
716
+ *
717
+ *
718
+ * @param {string} key
719
+ * @param {Function} [callback]
720
+ * @returns {*}
721
+ * @memberof MemoryCache
722
+ */
723
+ incr(key, callback) {
724
+ let retVal = null;
725
+ try {
726
+ retVal = this._addToKey(key, 1);
727
+ }
728
+ catch (err) {
729
+ return this._handleCallback(callback, null, err);
730
+ }
731
+ return this._handleCallback(callback, retVal);
732
+ }
733
+ /**
734
+ *
735
+ *
736
+ * @param {string} key
737
+ * @param {number} amount
738
+ * @param {Function} [callback]
739
+ * @returns {*}
740
+ * @memberof MemoryCache
741
+ */
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);
749
+ }
750
+ return this._handleCallback(callback, retVal);
751
+ }
752
+ /**
753
+ *
754
+ *
755
+ * @param {string} key
756
+ * @param {Function} [callback]
757
+ * @returns {*}
758
+ * @memberof MemoryCache
759
+ */
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);
786
+ }
787
+ return this._handleCallback(callback, retVal);
788
+ }
789
+ // ---------------------------------------
790
+ // ## Hash ##
791
+ // ---------------------------------------
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');
799
+ }
800
+ if (!this._hasField(key, field)) {
801
+ retVal = 1;
802
+ }
803
+ this._setField(key, field, value.toString());
804
+ this.persist(key);
805
+ return this._handleCallback(callback, retVal);
806
+ }
807
+ /**
808
+ *
809
+ *
810
+ * @param {string} key
811
+ * @param {string} field
812
+ * @param {Function} [callback]
813
+ * @returns {*}
814
+ * @memberof MemoryCache
815
+ */
816
+ hget(key, field, callback) {
817
+ let retVal = null;
818
+ if (this._hasKey(key)) {
819
+ this._testType(key, 'hash', true, callback);
820
+ if (this._hasField(key, field)) {
821
+ retVal = this._getKey(key)[field];
822
+ }
823
+ }
824
+ return this._handleCallback(callback, retVal);
825
+ }
826
+ /**
827
+ *
828
+ *
829
+ * @param {string} key
830
+ * @param {string} field
831
+ * @param {Function} [callback]
832
+ * @returns {*}
833
+ * @memberof MemoryCache
834
+ */
835
+ hexists(key, field, callback) {
836
+ let retVal = 0;
837
+ if (this._hasKey(key)) {
838
+ this._testType(key, 'hash', true, callback);
839
+ if (this._hasField(key, field)) {
840
+ retVal = 1;
841
+ }
842
+ }
843
+ return this._handleCallback(callback, retVal);
844
+ }
845
+ /**
846
+ *
847
+ *
848
+ * @param {string} key
849
+ * @param {...any[]} fields
850
+ * @returns {*}
851
+ * @memberof MemoryCache
852
+ */
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);
867
+ }
868
+ /**
869
+ *
870
+ *
871
+ * @param {string} key
872
+ * @param {Function} [callback]
873
+ * @returns {*}
874
+ * @memberof MemoryCache
875
+ */
876
+ hlen(key, callback) {
877
+ const retVal = this.hkeys(key).length;
878
+ return this._handleCallback(callback, retVal);
879
+ }
880
+ /**
881
+ *
882
+ *
883
+ * @param {string} key
884
+ * @param {string} field
885
+ * @param {*} value
886
+ * @param {Function} [callback]
887
+ * @returns {*}
888
+ * @memberof MemoryCache
889
+ */
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);
899
+ }
900
+ /**
901
+ *
902
+ *
903
+ * @param {string} key
904
+ * @param {Function} [callback]
905
+ * @returns {*}
906
+ * @memberof MemoryCache
907
+ */
908
+ hgetall(key, callback) {
909
+ let retVals = {};
910
+ if (this._hasKey(key)) {
911
+ this._testType(key, 'hash', true, callback);
912
+ retVals = this._getKey(key);
913
+ }
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
+ if (this._hasKey(key)) {
927
+ this._testType(key, 'hash', true, callback);
928
+ retVals = Object.keys(this._getKey(key));
929
+ }
930
+ return this._handleCallback(callback, retVals);
931
+ }
932
+ /**
933
+ *
934
+ *
935
+ * @param {string} key
936
+ * @param {Function} [callback]
937
+ * @returns {*}
938
+ * @memberof MemoryCache
939
+ */
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));
945
+ }
946
+ return this._handleCallback(callback, retVals);
947
+ }
948
+ // ---------------------------------------
949
+ // Lists (Array / Queue / Stack)
950
+ // ---------------------------------------
951
+ /**
952
+ *
953
+ *
954
+ * @param {string} key
955
+ * @param {Function} [callback]
956
+ * @returns {*}
957
+ * @memberof MemoryCache
958
+ */
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;
964
+ }
965
+ return this._handleCallback(callback, retVal);
966
+ }
967
+ /**
968
+ *
969
+ *
970
+ * @param {string} key
971
+ * @param {(string | number)} value
972
+ * @param {Function} [callback]
973
+ * @returns {*}
974
+ * @memberof MemoryCache
975
+ */
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);
989
+ }
990
+ /**
991
+ *
992
+ *
993
+ * @param {string} key
994
+ * @param {(string | number)} value
995
+ * @param {Function} [callback]
996
+ * @returns {*}
997
+ * @memberof MemoryCache
998
+ */
999
+ lpush(key, value, callback) {
1000
+ let retVal = 0;
1001
+ if (this._hasKey(key)) {
1002
+ this._testType(key, 'list', true, callback);
1003
+ }
1004
+ else {
1005
+ this.cache[key] = this._makeKey([], 'list');
1006
+ }
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);
1012
+ }
1013
+ /**
1014
+ *
1015
+ *
1016
+ * @param {string} key
1017
+ * @param {Function} [callback]
1018
+ * @returns {*}
1019
+ * @memberof MemoryCache
1020
+ */
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);
1030
+ }
1031
+ /**
1032
+ *
1033
+ *
1034
+ * @param {string} key
1035
+ * @param {Function} [callback]
1036
+ * @returns {*}
1037
+ * @memberof MemoryCache
1038
+ */
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);
1046
+ }
1047
+ return this._handleCallback(callback, retVal);
1048
+ }
1049
+ /**
1050
+ *
1051
+ *
1052
+ * @param {string} key
1053
+ * @param {number} start
1054
+ * @param {number} stop
1055
+ * @param {Function} [callback]
1056
+ * @returns {*}
1057
+ * @memberof MemoryCache
1058
+ */
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);
1085
+ }
1086
+ // ---------------------------------------
1087
+ // ## Sets (Unique Lists)##
1088
+ // ---------------------------------------
1089
+ /**
1090
+ *
1091
+ *
1092
+ * @param {string} key
1093
+ * @param {...any[]} members
1094
+ * @returns {*}
1095
+ * @memberof MemoryCache
1096
+ */
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);
1102
+ }
1103
+ else {
1104
+ this.cache[key] = this._makeKey([], 'set');
1105
+ }
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);
1113
+ }
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;
1127
+ }
1128
+ return this._handleCallback(callback, retVal);
1129
+ }
1130
+ /**
1131
+ *
1132
+ *
1133
+ * @param {string} key
1134
+ * @param {string} member
1135
+ * @param {Function} [callback]
1136
+ * @returns {*}
1137
+ * @memberof MemoryCache
1138
+ */
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
+ }
1147
+ }
1148
+ return this._handleCallback(callback, retVal);
1149
+ }
1150
+ /**
1151
+ *
1152
+ *
1153
+ * @param {string} key
1154
+ * @param {Function} [callback]
1155
+ * @returns {*}
1156
+ * @memberof MemoryCache
1157
+ */
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);
1165
+ }
1166
+ /**
1167
+ *
1168
+ *
1169
+ * @param {string} key
1170
+ * @param {number} [count]
1171
+ * @param {Function} [callback]
1172
+ * @returns {*}
1173
+ * @memberof MemoryCache
1174
+ */
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);
1180
+ }
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
+ }
1190
+ }
1191
+ return this._handleCallback(callback, retVal);
1192
+ }
1193
+ /**
1194
+ *
1195
+ *
1196
+ * @param {string} key
1197
+ * @param {...any[]} members
1198
+ * @returns {*}
1199
+ * @memberof MemoryCache
1200
+ */
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);
1220
+ }
1221
+ /**
1222
+ *
1223
+ *
1224
+ * @param {string} sourcekey
1225
+ * @param {string} destkey
1226
+ * @param {string} member
1227
+ * @param {Function} [callback]
1228
+ * @returns {*}
1229
+ * @memberof MemoryCache
1230
+ */
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
+ }
1242
+ }
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 = [];
1259
+ }
1260
+ else if (!silent) {
1261
+ return this._handleCallback(callback, null, messages.nomultidiscard);
1262
+ }
1263
+ return this._handleCallback(callback, messages.ok);
1264
+ }
1265
+ // ---------------------------------------
1266
+ // ## Internal - Key ##
1267
+ // ---------------------------------------
1268
+ /**
1269
+ *
1270
+ *
1271
+ * @param {string} key
1272
+ * @param {Function} [callback]
1273
+ * @returns {*}
1274
+ * @memberof MemoryCache
1275
+ */
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
+ }
1285
+ }
1286
+ else {
1287
+ retVal = -1;
1288
+ }
1289
+ }
1290
+ return this._handleCallback(callback, retVal);
1291
+ }
1292
+ /**
1293
+ *
1294
+ *
1295
+ * @private
1296
+ * @param {string} key
1297
+ * @param {Function} [callback]
1298
+ * @returns {*}
1299
+ * @memberof MemoryCache
1300
+ */
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
+ }
1308
+ }
1309
+ return this._handleCallback(callback, retVal);
1310
+ }
1311
+ /**
1312
+ *
1313
+ *
1314
+ * @private
1315
+ * @param {string} key
1316
+ * @returns {*} {boolean}
1317
+ * @memberof MemoryCache
1318
+ */
1319
+ _hasKey(key) {
1320
+ return this.cache.hasOwnProperty(key);
1321
+ }
1322
+ /**
1323
+ *
1324
+ *
1325
+ * @private
1326
+ * @param {*} value
1327
+ * @param {string} type
1328
+ * @param {number} timeout
1329
+ * @returns {*}
1330
+ * @memberof MemoryCache
1331
+ */
1332
+ _makeKey(value, type, timeout) {
1333
+ return { value: value, type: type, timeout: timeout || null, lastAccess: Date.now() };
1334
+ }
1335
+ /**
1336
+ *
1337
+ *
1338
+ * @private
1339
+ * @param {string} key
1340
+ * @returns {*}
1341
+ * @memberof MemoryCache
1342
+ */
1343
+ _key(key) {
1344
+ this.cache[key].lastAccess = Date.now();
1345
+ return this.cache[key];
1346
+ }
1347
+ /**
1348
+ *
1349
+ *
1350
+ * @private
1351
+ * @param {string} key
1352
+ * @param {number} amount
1353
+ * @param {Function} [callback]
1354
+ * @returns {*}
1355
+ * @memberof MemoryCache
1356
+ */
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');
1371
+ }
1372
+ const val = keyValue + amount;
1373
+ this._setKey(key, val.toString());
1374
+ return val;
1375
+ }
1376
+ /**
1377
+ *
1378
+ *
1379
+ * @private
1380
+ * @param {string} key
1381
+ * @param {string} type
1382
+ * @param {boolean} [throwError]
1383
+ * @param {Function} [callback]
1384
+ * @returns {*}
1385
+ * @memberof MemoryCache
1386
+ */
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;
1395
+ }
1396
+ return true;
1397
+ }
1398
+ /**
1399
+ *
1400
+ *
1401
+ * @private
1402
+ * @param {string} key
1403
+ * @returns {*}
1404
+ * @memberof MemoryCache
1405
+ */
1406
+ _getKey(key) {
1407
+ const _key = this._key(key) || {};
1408
+ if (_key.timeout && _key.timeout <= Date.now()) {
1409
+ this.del(key);
1410
+ return null;
1411
+ }
1412
+ return _key.value;
1413
+ }
1414
+ /**
1415
+ *
1416
+ *
1417
+ * @private
1418
+ * @param {string} key
1419
+ * @param {(number | string)} value
1420
+ * @memberof MemoryCache
1421
+ */
1422
+ _setKey(key, value) {
1423
+ this.cache[key].value = value;
1424
+ this.cache[key].lastAccess = Date.now();
1425
+ }
1426
+ /**
1427
+ *
1428
+ *
1429
+ * @private
1430
+ * @param {string} key
1431
+ * @param {string} field
1432
+ * @param {number} [amount]
1433
+ * @param {boolean} [useFloat]
1434
+ * @param {Function} [callback]
1435
+ * @returns {*}
1436
+ * @memberof MemoryCache
1437
+ */
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
+ }
1450
+ }
1451
+ else {
1452
+ this.cache[key] = this._makeKey({}, 'hash');
1453
+ }
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);
1458
+ }
1459
+ fieldValue += amount;
1460
+ this._setField(key, field, fieldValue.toString());
1461
+ return fieldValue;
1462
+ }
1463
+ /**
1464
+ *
1465
+ *
1466
+ * @private
1467
+ * @param {string} key
1468
+ * @param {string} field
1469
+ * @returns {*}
1470
+ * @memberof MemoryCache
1471
+ */
1472
+ _getField(key, field) {
1473
+ return this._getKey(key)[field];
1474
+ }
1475
+ /**
1476
+ *
1477
+ *
1478
+ * @private
1479
+ * @param {string} key
1480
+ * @param {string} field
1481
+ * @returns {*} {boolean}
1482
+ * @memberof MemoryCache
1483
+ */
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
+ }
1491
+ }
1492
+ return retVal;
1493
+ }
1494
+ /**
1495
+ *
1496
+ *
1497
+ * @param {string} key
1498
+ * @param {string} field
1499
+ * @param {*} value
1500
+ * @memberof MemoryCache
1501
+ */
1502
+ _setField(key, field, value) {
1503
+ this._getKey(key)[field] = value;
1504
+ }
1505
+ /**
1506
+ *
1507
+ *
1508
+ * @private
1509
+ * @param {Function} [callback]
1510
+ * @param {(any)} [message]
1511
+ * @param {*} [error]
1512
+ * @param {boolean} [nolog]
1513
+ * @returns {*}
1514
+ * @memberof MemoryCache
1515
+ */
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;
1532
+ }
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;
1546
+ }
1547
+ /**
1548
+ *
1549
+ *
1550
+ * @private
1551
+ * @param {any[]} [params]
1552
+ * @returns {*}
1553
+ * @memberof MemoryCache
1554
+ */
1555
+ _retrieveCallback(params) {
1556
+ if (Array.isArray(params) && params.length > 0 && typeof params[params.length - 1] === 'function') {
1557
+ return params.pop();
1558
+ }
1559
+ return;
1560
+ }
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
+ /**
1573
+ * Creates an instance of MemoryStore.
1574
+ * @param {StoreOptions} options
1575
+ * @memberof MemoryStore
1576
+ */
1577
+ constructor(options) {
1578
+ super(options);
1579
+ this.options = options;
1580
+ this.client = null;
1581
+ }
1582
+ /**
1583
+ * getConnection
1584
+ *
1585
+ * @returns {*}
1586
+ * @memberof MemoryStore
1587
+ */
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;
1599
+ }
1600
+ /**
1601
+ * close
1602
+ *
1603
+ * @returns {*} {Promise<void>}
1604
+ * @memberof MemoryStore
1605
+ */
1606
+ async close() {
1607
+ this.client.end();
1608
+ this.client = null;
1609
+ }
1610
+ /**
1611
+ * release
1612
+ *
1613
+ * @param {*} conn
1614
+ * @returns {*} {Promise<void>}
1615
+ * @memberof MemoryStore
1616
+ */
1617
+ async release(conn) {
1618
+ return;
1619
+ }
1620
+ /**
1621
+ * defineCommand
1622
+ *
1623
+ * @param {string} name
1624
+ * @param {*} scripts
1625
+ * @memberof MemoryStore
1626
+ */
1627
+ async defineCommand(name, scripts) {
1628
+ throw new Error(messages.unsupported);
1629
+ }
1630
+ /**
1631
+ * get and compare value
1632
+ *
1633
+ * @param {string} name
1634
+ * @param {(string | number)} value
1635
+ * @returns {*} {Promise<any>}
1636
+ * @memberof MemoryStore
1637
+ */
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;
1649
+ }
1650
+ }
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
+ /**
1669
+ * Creates an instance of RedisStore.
1670
+ * @param {StoreOptions} options
1671
+ * @memberof RedisStore
1672
+ */
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];
1723
+ }
1724
+ }
1725
+ return opt;
1726
+ }
1727
+ /**
1728
+ * create connection by native
1729
+ *
1730
+ * @param {number} [connNum=0]
1731
+ * @returns {*} {Promise<IORedis.Redis | IORedis.Cluster>}
1732
+ * @memberof RedisStore
1733
+ */
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');
1754
+ }
1755
+ });
1756
+ connection.on('ready', () => {
1757
+ this.client = connection;
1758
+ defer.resolve(connection);
1759
+ });
1760
+ return defer.promise;
1761
+ }
1762
+ /**
1763
+ * get connection from pool
1764
+ *
1765
+ * @returns {*}
1766
+ * @memberof RedisStore
1767
+ */
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();
1793
+ }
1794
+ /**
1795
+ * close connection
1796
+ *
1797
+ * @returns {*}
1798
+ * @memberof RedisStore
1799
+ */
1800
+ async close() {
1801
+ this.client.disconnect();
1802
+ this.client = null;
1803
+ this.pool.destroy(this.client);
1804
+ this.pool = null;
1805
+ return;
1806
+ }
1807
+ /**
1808
+ *
1809
+ *
1810
+ * @param {*} conn
1811
+ * @returns {*}
1812
+ * @memberof RedisStore
1813
+ */
1814
+ async release(conn) {
1815
+ if (this.pool.isBorrowedResource(conn)) {
1816
+ return this.pool.release(conn);
1817
+ }
1818
+ return Promise.resolve();
1819
+ }
1820
+ /**
1821
+ * defineCommand
1822
+ *
1823
+ * @param {string} name
1824
+ * @param {{ numberOfKeys?: number; lua?: string; }} scripts
1825
+ * @returns {*}
1826
+ * @memberof RedisStore
1827
+ */
1828
+ async defineCommand(name, scripts) {
1829
+ const conn = await this.getConnection();
1830
+ if (!conn[name]) {
1831
+ conn.defineCommand(name, scripts);
1832
+ }
1833
+ return conn;
1834
+ }
1835
+ /**
1836
+ * get and compare value
1837
+ *
1838
+ * @param {string} name
1839
+ * @param {(string | number)} value
1840
+ * @returns {*} {Promise<any>}
1841
+ * @memberof RedisStore
1842
+ */
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
+ }
1868
+ }
1869
+ }
1870
+
1871
+ /**
1872
+ *
1873
+ *
1874
+ * @export
1875
+ * @class Store
1876
+ */
1877
+ class Store {
1878
+ /**
1879
+ *
1880
+ *
1881
+ * @static
1882
+ * @returns
1883
+ * @memberof ValidateUtil
1884
+ */
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;
1909
+ }
1910
+ return this.instance;
1911
+ }
1912
+ }
1913
+
1914
+ exports.CacheStore = CacheStore;
1915
+ exports.MemoryStore = MemoryStore;
53
1916
  exports.Store = Store;
54
- //# sourceMappingURL=index.js.map