node-karin 1.11.1 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # 更新日志
2
2
 
3
+ ## [1.11.3](https://github.com/KarinJS/Karin/compare/core-v1.11.2...core-v1.11.3) (2025-10-07)
4
+
5
+
6
+ ### 🐛 Bug Fixes
7
+
8
+ * correct Redis mock SET method options handling and type checking ([#546](https://github.com/KarinJS/Karin/issues/546)) ([fb6a999](https://github.com/KarinJS/Karin/commit/fb6a99957974932d7222eb0be1510906483d4483))
9
+
10
+ ## [1.11.2](https://github.com/KarinJS/Karin/compare/core-v1.11.1...core-v1.11.2) (2025-10-07)
11
+
12
+
13
+ ### 🐛 Bug Fixes
14
+
15
+ * 修复 Redis Mock 客户端缺少 setEx 等常用方法的问题 ([#543](https://github.com/KarinJS/Karin/issues/543)) ([3797b4f](https://github.com/KarinJS/Karin/commit/3797b4f7721df1428f0f5b068fb77fda017a3792))
16
+
3
17
  ## [1.11.1](https://github.com/KarinJS/Karin/compare/core-v1.11.0...core-v1.11.1) (2025-10-02)
4
18
 
5
19
 
package/dist/index.mjs CHANGED
@@ -20449,21 +20449,58 @@ var init_mock = __esm({
20449
20449
  const PXAT = Number(options.PXAT);
20450
20450
  if (!isNaN(PXAT)) expire = PXAT;
20451
20451
  this.store[key] = { type: "str" /* STR */, expire };
20452
+ this.#str[key] = value;
20452
20453
  } else if (options?.KEEPTTL) {
20453
- if (this.#str[key]) {
20454
+ if (this.#str[key] && this.store[key]) {
20454
20455
  this.#str[key] = value;
20456
+ expire = this.store[key].expire;
20455
20457
  } else {
20456
20458
  this.store[key] = { type: "str" /* STR */, expire: -1 };
20457
20459
  this.#str[key] = value;
20460
+ expire = -1;
20458
20461
  }
20459
20462
  } else if (options?.NX) {
20460
- if (!this.#str[key]) {
20463
+ if (!this.store[key] || this.checkExpire(key, false)) {
20461
20464
  this.store[key] = { type: "str" /* STR */, expire: -1 };
20462
20465
  this.#str[key] = value;
20466
+ this.#sqlite.set(key, value, "str" /* STR */, -1);
20463
20467
  }
20468
+ return "OK";
20464
20469
  } else if (options?.XX) {
20465
- if (this.#str[key]) {
20470
+ if (this.store[key]) {
20471
+ const currentExpire = this.store[key].expire;
20472
+ const oldType = this.store[key].type;
20473
+ if (oldType !== "str" /* STR */) {
20474
+ switch (oldType) {
20475
+ case "num" /* NUM */:
20476
+ delete this.#num[key];
20477
+ break;
20478
+ case "hash" /* HASH */:
20479
+ delete this.#hash[key];
20480
+ break;
20481
+ case "list" /* LIST */:
20482
+ delete this.#list[key];
20483
+ break;
20484
+ case "set" /* SET */:
20485
+ delete this.#set[key];
20486
+ break;
20487
+ case "zset" /* ZSET */:
20488
+ delete this.#zset[key];
20489
+ break;
20490
+ case "pf" /* PF */:
20491
+ delete this.#pf[key];
20492
+ break;
20493
+ case "bit" /* BIT */:
20494
+ delete this.#bit[key];
20495
+ break;
20496
+ }
20497
+ }
20498
+ this.store[key] = { type: "str" /* STR */, expire: currentExpire };
20466
20499
  this.#str[key] = value;
20500
+ this.#sqlite.set(key, value, "str" /* STR */, currentExpire);
20501
+ return "OK";
20502
+ } else {
20503
+ return null;
20467
20504
  }
20468
20505
  } else if (options?.GET) {
20469
20506
  this.store[key] = { type: "str" /* STR */, expire: -1 };
@@ -20497,6 +20534,84 @@ var init_mock = __esm({
20497
20534
  return this.#str[key].toString();
20498
20535
  }
20499
20536
  }
20537
+ /**
20538
+ * @description 设置键值对并指定过期时间(秒)
20539
+ * @param key 键
20540
+ * @param seconds 过期时间(秒)
20541
+ * @param value 值
20542
+ */
20543
+ async setEx(key, seconds, value) {
20544
+ return await this.set(key, value, { EX: seconds });
20545
+ }
20546
+ /**
20547
+ * @description 设置键值对并指定过期时间(毫秒)
20548
+ * @param key 键
20549
+ * @param milliseconds 过期时间(毫秒)
20550
+ * @param value 值
20551
+ */
20552
+ async pSetEx(key, milliseconds, value) {
20553
+ return await this.set(key, value, { PX: milliseconds });
20554
+ }
20555
+ /**
20556
+ * @description 仅当键不存在时设置键值对
20557
+ * @param key 键
20558
+ * @param value 值
20559
+ * @returns 返回 1 表示键已设置,0 表示键已存在
20560
+ */
20561
+ async setNX(key, value) {
20562
+ if (this.store[key] && !this.checkExpire(key)) {
20563
+ return 0;
20564
+ }
20565
+ await this.set(key, value, { NX: true });
20566
+ return 1;
20567
+ }
20568
+ /**
20569
+ * @description 获取键值并设置过期时间
20570
+ * @param key 键
20571
+ * @param options 过期时间选项(EX: 秒, PX: 毫秒, EXAT: 秒级时间戳, PXAT: 毫秒级时间戳)
20572
+ */
20573
+ async getEx(key, options) {
20574
+ const value = await this.get(key);
20575
+ if (value === null) return null;
20576
+ if (options?.PERSIST) {
20577
+ if (this.store[key]) {
20578
+ this.store[key].expire = -1;
20579
+ const { type } = this.store[key];
20580
+ const currentValue = this.getValueStringByKey(key);
20581
+ this.#sqlite.set(key, currentValue, type, -1);
20582
+ }
20583
+ } else if (options?.EX !== void 0) {
20584
+ await this.expire(key, options.EX);
20585
+ } else if (options?.PX !== void 0) {
20586
+ const expire = moment().add(options.PX, "milliseconds").valueOf();
20587
+ this.store[key].expire = expire;
20588
+ const { type } = this.store[key];
20589
+ const currentValue = this.getValueStringByKey(key);
20590
+ this.#sqlite.set(key, currentValue, type, expire);
20591
+ } else if (options?.EXAT !== void 0) {
20592
+ this.store[key].expire = options.EXAT * 1e3;
20593
+ const { type } = this.store[key];
20594
+ const currentValue = this.getValueStringByKey(key);
20595
+ this.#sqlite.set(key, currentValue, type, options.EXAT * 1e3);
20596
+ } else if (options?.PXAT !== void 0) {
20597
+ this.store[key].expire = options.PXAT;
20598
+ const { type } = this.store[key];
20599
+ const currentValue = this.getValueStringByKey(key);
20600
+ this.#sqlite.set(key, currentValue, type, options.PXAT);
20601
+ }
20602
+ return value;
20603
+ }
20604
+ /**
20605
+ * @description 获取键值并删除键
20606
+ * @param key 键
20607
+ */
20608
+ async getDel(key) {
20609
+ const value = await this.get(key);
20610
+ if (value !== null) {
20611
+ await this.del(key);
20612
+ }
20613
+ return value;
20614
+ }
20500
20615
  /**
20501
20616
  * @description 删除键
20502
20617
  * @param key 键
@@ -20527,6 +20642,53 @@ var init_mock = __esm({
20527
20642
  this.#sqlite.expire(key, expire);
20528
20643
  return 1;
20529
20644
  }
20645
+ /**
20646
+ * @description 设置键的过期时间戳(秒)
20647
+ * @param key 键
20648
+ * @param timestamp 过期时间戳(秒)
20649
+ */
20650
+ async expireAt(key, timestamp) {
20651
+ if (!this.store[key]) return 0;
20652
+ this.store[key].expire = timestamp * 1e3;
20653
+ this.#sqlite.expire(key, timestamp * 1e3);
20654
+ return 1;
20655
+ }
20656
+ /**
20657
+ * @description 设置键的过期时间(毫秒)
20658
+ * @param key 键
20659
+ * @param milliseconds 过期时间(毫秒)
20660
+ */
20661
+ async pExpire(key, milliseconds) {
20662
+ if (!this.store[key]) return 0;
20663
+ const expire = moment().add(milliseconds, "milliseconds").valueOf();
20664
+ this.store[key].expire = expire;
20665
+ this.#sqlite.expire(key, expire);
20666
+ return 1;
20667
+ }
20668
+ /**
20669
+ * @description 设置键的过期时间戳(毫秒)
20670
+ * @param key 键
20671
+ * @param timestamp 过期时间戳(毫秒)
20672
+ */
20673
+ async pExpireAt(key, timestamp) {
20674
+ if (!this.store[key]) return 0;
20675
+ this.store[key].expire = timestamp;
20676
+ this.#sqlite.expire(key, timestamp);
20677
+ return 1;
20678
+ }
20679
+ /**
20680
+ * @description 移除键的过期时间
20681
+ * @param key 键
20682
+ */
20683
+ async persist(key) {
20684
+ if (!this.store[key]) return 0;
20685
+ if (this.store[key].expire === -1) return 0;
20686
+ this.store[key].expire = -1;
20687
+ const { type } = this.store[key];
20688
+ const currentValue = this.getValueStringByKey(key);
20689
+ this.#sqlite.set(key, currentValue, type, -1);
20690
+ return 1;
20691
+ }
20530
20692
  /**
20531
20693
  * @description 获取键的过期时间
20532
20694
  * @param key 键
@@ -20537,6 +20699,100 @@ var init_mock = __esm({
20537
20699
  if (this.checkExpire(key)) return -2;
20538
20700
  return moment(this.store[key].expire).diff(moment(), "seconds");
20539
20701
  }
20702
+ /**
20703
+ * @description 获取键的过期时间(毫秒)
20704
+ * @param key 键
20705
+ */
20706
+ async pTTL(key) {
20707
+ if (!this.store[key]) return -2;
20708
+ if (this.store[key].expire === -1) return -1;
20709
+ if (this.checkExpire(key)) return -2;
20710
+ return moment(this.store[key].expire).diff(moment(), "milliseconds");
20711
+ }
20712
+ /**
20713
+ * @description 获取字符串长度
20714
+ * @param key 键
20715
+ */
20716
+ async strLen(key) {
20717
+ if (!this.store[key]) return 0;
20718
+ if (this.checkExpire(key)) return 0;
20719
+ const { type } = this.store[key];
20720
+ if (type === "str" /* STR */) {
20721
+ return this.#str[key].length;
20722
+ }
20723
+ return 0;
20724
+ }
20725
+ /**
20726
+ * @description 重命名键
20727
+ * @param key 原键名
20728
+ * @param newKey 新键名
20729
+ */
20730
+ async rename(key, newKey) {
20731
+ if (!this.store[key]) throw new Error("no such key");
20732
+ const { type, expire } = this.store[key];
20733
+ const value = this.getValueStringByKey(key);
20734
+ this.#del(key);
20735
+ this.store[newKey] = { type, expire };
20736
+ switch (type) {
20737
+ case "str" /* STR */:
20738
+ this.#str[newKey] = value;
20739
+ break;
20740
+ case "num" /* NUM */:
20741
+ this.#num[newKey] = Number(value);
20742
+ break;
20743
+ case "hash" /* HASH */:
20744
+ this.#hash[newKey] = JSON.parse(value);
20745
+ break;
20746
+ case "list" /* LIST */:
20747
+ this.#list[newKey] = JSON.parse(value);
20748
+ break;
20749
+ case "set" /* SET */:
20750
+ this.#set[newKey] = new Set(JSON.parse(value));
20751
+ break;
20752
+ case "zset" /* ZSET */:
20753
+ this.#zset[newKey] = JSON.parse(value);
20754
+ break;
20755
+ case "pf" /* PF */:
20756
+ this.#pf[newKey] = new Set(JSON.parse(value));
20757
+ break;
20758
+ case "bit" /* BIT */:
20759
+ this.#bit[newKey] = Buffer.from(value, "base64");
20760
+ break;
20761
+ }
20762
+ this.#sqlite.set(newKey, value, type, expire);
20763
+ return "OK";
20764
+ }
20765
+ /**
20766
+ * @description 仅当新键不存在时重命名键
20767
+ * @param key 原键名
20768
+ * @param newKey 新键名
20769
+ */
20770
+ async renameNX(key, newKey) {
20771
+ if (!this.store[key]) return 0;
20772
+ if (this.store[newKey] && !this.checkExpire(newKey)) return 0;
20773
+ await this.rename(key, newKey);
20774
+ return 1;
20775
+ }
20776
+ /**
20777
+ * @description 返回数据库中键的数量
20778
+ */
20779
+ async dbSize() {
20780
+ const keys = Object.keys(this.store);
20781
+ keys.forEach((key) => this.checkExpire(key));
20782
+ return Object.keys(this.store).length;
20783
+ }
20784
+ /**
20785
+ * @description 从数据库中随机返回一个键
20786
+ */
20787
+ async randomKey() {
20788
+ const keys = Object.keys(this.store);
20789
+ if (keys.length === 0) return null;
20790
+ keys.forEach((key) => this.checkExpire(key));
20791
+ const validKeys = Object.keys(this.store);
20792
+ if (validKeys.length === 0) return null;
20793
+ const randomIndex = Math.floor(Math.random() * validKeys.length);
20794
+ return validKeys[randomIndex];
20795
+ }
20540
20796
  /**
20541
20797
  * @description 获取所有键
20542
20798
  * @param pattern 匹配规则
@@ -20584,6 +20840,40 @@ var init_mock = __esm({
20584
20840
  this.#sqlite.set(key, String(this.#num[key]), "num" /* NUM */, this.store[key].expire);
20585
20841
  return this.#num[key];
20586
20842
  }
20843
+ /**
20844
+ * @description 自增指定值
20845
+ * @param key 键
20846
+ * @param increment 增量
20847
+ */
20848
+ async incrBy(key, increment) {
20849
+ if (!this.#num[key]) {
20850
+ this.#num[key] = 0;
20851
+ this.store[key] = { type: "num" /* NUM */, expire: -1 };
20852
+ } else if (this.checkExpire(key, false)) {
20853
+ this.store[key].expire = -1;
20854
+ this.#num[key] = 0;
20855
+ }
20856
+ this.#num[key] += increment;
20857
+ this.#sqlite.set(key, String(this.#num[key]), "num" /* NUM */, this.store[key].expire);
20858
+ return this.#num[key];
20859
+ }
20860
+ /**
20861
+ * @description 自增指定浮点值
20862
+ * @param key 键
20863
+ * @param increment 增量(浮点数)
20864
+ */
20865
+ async incrByFloat(key, increment) {
20866
+ if (!this.#num[key]) {
20867
+ this.#num[key] = 0;
20868
+ this.store[key] = { type: "num" /* NUM */, expire: -1 };
20869
+ } else if (this.checkExpire(key, false)) {
20870
+ this.store[key].expire = -1;
20871
+ this.#num[key] = 0;
20872
+ }
20873
+ this.#num[key] += increment;
20874
+ this.#sqlite.set(key, String(this.#num[key]), "num" /* NUM */, this.store[key].expire);
20875
+ return this.#num[key];
20876
+ }
20587
20877
  /**
20588
20878
  * @description 自减
20589
20879
  * @param key 键
@@ -20600,6 +20890,23 @@ var init_mock = __esm({
20600
20890
  this.#sqlite.set(key, String(this.#num[key]), "num" /* NUM */, this.store[key].expire);
20601
20891
  return this.#num[key];
20602
20892
  }
20893
+ /**
20894
+ * @description 自减指定值
20895
+ * @param key 键
20896
+ * @param decrement 减量
20897
+ */
20898
+ async decrBy(key, decrement) {
20899
+ if (!this.#num[key]) {
20900
+ this.#num[key] = 0;
20901
+ this.store[key] = { type: "num" /* NUM */, expire: -1 };
20902
+ } else if (this.checkExpire(key, false)) {
20903
+ this.store[key].expire = -1;
20904
+ this.#num[key] = 0;
20905
+ }
20906
+ this.#num[key] -= decrement;
20907
+ this.#sqlite.set(key, String(this.#num[key]), "num" /* NUM */, this.store[key].expire);
20908
+ return this.#num[key];
20909
+ }
20603
20910
  /**
20604
20911
  * @description 追加字符串
20605
20912
  * @param key 键
@@ -20909,46 +21216,6 @@ var init_mock = __esm({
20909
21216
  if (this.checkExpire(key)) return 0;
20910
21217
  return this.#pf[key].size;
20911
21218
  }
20912
- /**
20913
- * 合并多个 HyperLogLog
20914
- * @param destKey 目标 HyperLogLog 的键
20915
- * @param sourceKeys 源 HyperLogLog 的键
20916
- * @returns 返回 1 表示合并成功,0 表示合并失败
20917
- */
20918
- async pExpire(key, seconds) {
20919
- if (!this.#pf[key]) return false;
20920
- this.store[key].expire = moment().add(seconds, "seconds").valueOf();
20921
- this.#sqlite.set(key, JSON.stringify(this.#pf[key]), "pf" /* PF */, this.store[key].expire);
20922
- return true;
20923
- }
20924
- /**
20925
- * 设置 HyperLogLog 的过期时间
20926
- * @param key HyperLogLog 的键
20927
- * @param seconds 过期时间(秒)
20928
- * @returns 返回 1 表示设置成功,0 表示设置失败
20929
- */
20930
- async pTTL(key) {
20931
- if (!this.#pf[key]) return -2;
20932
- if (this.store[key].expire === -1) return -1;
20933
- if (this.checkExpire(key)) return -2;
20934
- const ttl = moment(this.store[key].expire).diff(moment(), "seconds");
20935
- this.store[key].expire = ttl;
20936
- this.#sqlite.set(key, JSON.stringify(this.#pf[key]), "pf" /* PF */, this.store[key].expire);
20937
- return ttl;
20938
- }
20939
- /**
20940
- * 为键设置到某个特定时间点的过期时间
20941
- * @param key HyperLogLog 的键
20942
- * @param seconds 过期时间(毫秒)
20943
- * @returns 返回布尔值
20944
- */
20945
- async pExpireAt(key, timestamp) {
20946
- if (!this.#pf[key]) return false;
20947
- if (this.checkExpire(key)) return false;
20948
- this.store[key].expire = timestamp;
20949
- this.#sqlite.set(key, JSON.stringify(this.#pf[key]), "pf" /* PF */, this.store[key].expire);
20950
- return true;
20951
- }
20952
21219
  /**
20953
21220
  * @description 发布消息到频道
20954
21221
  * @param channel 频道
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-karin",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "Lightweight, efficient, concise, and stable robot framework.",
5
5
  "keywords": [
6
6
  "node",