mm_redis 1.9.5 → 1.9.7

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/README.md CHANGED
@@ -7,8 +7,8 @@ mm_redis是一个高效的Redis客户端封装库,提供了全面的Redis功
7
7
 
8
8
  ## 版本信息
9
9
 
10
- - **当前版本**: 1.9.4
11
- - **更新日期**: 2024-12-20
10
+ - **当前版本**: 1.9.6
11
+ - **更新日期**: 2024-12-21
12
12
  - **作者**: 邱文武
13
13
  - **NPM**: [https://www.npmjs.com/package/mm_redis](https://www.npmjs.com/package/mm_redis)
14
14
 
@@ -74,6 +74,15 @@ redis.setConfig('./config.json');
74
74
  ```
75
75
  ## 变更日志
76
76
 
77
+ ### v1.9.5 (2024-12-21)
78
+ - 修复hmset和hgetall方法的兼容性问题,确保与Redis客户端v5兼容
79
+ - 移除已废弃的hexists、hkeys和hvals方法,优化API设计
80
+ - 优化mget和mset方法的实现,确保与Redis v5 API完全兼容
81
+ - 更新测试脚本,移除对已废弃方法的调用
82
+ - 更新兼容性表格,确保文档与实际API一致
83
+ - 修复原生Redis API调用中的错误,提升代码稳定性
84
+ - 优化连接池管理,修复潜在的内存泄漏问题
85
+
77
86
  ### v1.9.4 (2024-12-20)
78
87
  - 优化了配置引入方式,支持对象配置和文件路径配置两种方式
79
88
  - 改进了setConfig方法的实现,使用Object.assign替代原来的合并方式
@@ -149,15 +158,6 @@ const name = await redis.hget('user:profile:1', 'name');
149
158
  const profile = await redis.hgetall('user:profile:1');
150
159
  $.log.debug('[Redis] 用户资料:', profile);
151
160
 
152
- // 获取哈希的所有字段名
153
- const fields = await redis.hkeys('user:profile:1');
154
-
155
- // 获取哈希的所有字段值
156
- const values = await redis.hvals('user:profile:1');
157
-
158
- // 判断哈希字段是否存在
159
- const hasEmail = await redis.hexists('user:profile:1', 'email');
160
-
161
161
  // 获取哈希字段数量
162
162
  const fieldCount = await redis.hlen('user:profile:1');
163
163
 
@@ -335,10 +335,7 @@ redis.on('set_error', (data) => {
335
335
  - `hmset(key, obj)`: 批量设置哈希字段
336
336
  - `hget(key, field)`: 获取哈希字段值
337
337
  - `hgetall(key)`: 获取哈希的所有字段和值
338
- - `hkeys(key)`: 获取哈希的所有字段名
339
- - `hvals(key)`: 获取哈希的所有字段值
340
338
  - `hdel(key, fields)`: 删除哈希字段
341
- - `hexists(key, field)`: 判断哈希字段是否存在
342
339
  - `hlen(key)`: 获取哈希字段数量
343
340
 
344
341
  ### 批量操作
@@ -415,6 +412,21 @@ redis.on('set_error', (data) => {
415
412
 
416
413
  ## 版本更新
417
414
 
415
+ ### 1.9.5 (2024-12-21)
416
+ - 修复hmset和hgetall方法的兼容性问题,确保与Redis客户端v5兼容
417
+ - 移除已废弃的hexists、hkeys和hvals方法,优化API设计
418
+ - 优化mget和mset方法的实现,确保与Redis v5 API完全兼容
419
+ - 更新测试脚本,移除对已废弃方法的调用
420
+ - 更新兼容性表格,确保文档与实际API一致
421
+ - 修复原生Redis API调用中的错误,提升代码稳定性
422
+ - 优化连接池管理,修复潜在的内存泄漏问题
423
+
424
+ ### 1.9.4 (2024-12-20)
425
+ - 优化了配置引入方式,支持对象配置和文件路径配置两种方式
426
+ - 改进了setConfig方法的实现,使用Object.assign替代原来的合并方式
427
+ - 修复了连接池相关的警告信息
428
+ - 增强了错误处理机制
429
+
418
430
  ### 1.9.0 (2024-11-20)
419
431
  - 适配Redis v4 API,确保与最新版Redis客户端兼容
420
432
  - 重写pipeline方法,使用Redis v4推荐的实现方式
@@ -1,64 +1,103 @@
1
- ```markdown
2
- # 三种缓存方式方法兼容性对比表格
1
+ # 四种缓存方式方法兼容性对比表格
3
2
 
4
3
  ## 核心缓存方法
5
4
 
6
- | 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
7
- |-------|-------|---------|-----------|----------|
8
- | set | ✅ | ✅ | ✅ | 完全兼容 |
9
- | get | ✅ | ✅ | ✅ | 完全兼容 |
10
- | del | ✅ | ✅ | ✅ | 完全兼容 |
11
- | has | ❌ | ✅ | ✅ | Redis无此方法,CacheBase保持兼容 |
12
- | clear | ❌ | ✅ | ✅ | Redis无此方法,CacheBase保持兼容 |
13
- | keys | ✅ | ✅ | ✅ | 完全兼容 |
14
- | ttl | ✅ | ❌ | ✅ | Redis原生支持,CacheBase模拟实现 |
15
- | persist | ✅ | ❌ | ✅ | Redis原生支持,CacheBase模拟实现 |
16
- | add | ❌ | ✅ | ✅ | Redis无此方法,CacheBase保持兼容 |
17
- | addInt | ❌ | ✅ | ✅ | Redis无此方法,CacheBase保持兼容 |
18
- | addStr | ❌ | ✅ | ✅ | Redis无此方法,CacheBase保持兼容 |
19
- | sort | ✅ | ❌ | ✅ | Redis原生支持,CacheBase模拟实现 |
5
+ | 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
6
+ |-------|-------|---------|-----------|--------|----------|
7
+ | set | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
8
+ | get | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
9
+ | del | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
10
+ | has | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
11
+ | clear | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
12
+ | keys | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
13
+ | ttl | ⚠️ | ⚠️ | ⚠️ | ⚠️ | 所有方式行为不一致,需要依赖底层实现 |
14
+ | add | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
15
+ | addInt | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
16
+ | addStr | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
17
+ | sort | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
18
+ | exists | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
19
+ | incrby | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
20
+ | decrby | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
21
+ | addFloat | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
20
22
 
21
23
  ## Redis兼容方法 - 哈希表操作
22
24
 
23
- | 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
24
- |-------|-------|---------|-----------|----------|
25
- | hset | ✅ | ✅ | ✅ | 模拟实现,通过set对象方式 |
26
- | hget | ✅ | ✅ | ✅ | 模拟实现,通过get对象方式 |
27
- | hgetall | ✅ | ✅ | ✅ | 模拟实现,返回完整对象 |
28
- | hdel | ✅ | ✅ | ✅ | 模拟实现,删除对象属性 |
29
- | hexists | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
30
- | hkeys | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
31
- | hvals | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
25
+ | 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
26
+ |-------|-------|---------|-----------|--------|----------|
27
+ | hset | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
28
+ | hget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
29
+ | hgetall | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
30
+ | hdel | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
31
+ | hmset | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
32
+ | hmget | ❌ | ✅ | ❌ | ❌ | 仅MongoDB支持 |
33
+ | hlen | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
34
+
35
+ ## Redis兼容方法 - 其他常用命令
36
+
37
+ | 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
38
+ |-------|-------|---------|-----------|--------|----------|
39
+ | expire | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
40
+ | incr | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
41
+ | decr | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
42
+ | mget | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
43
+ | mset | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
44
+ | pexpire | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
45
+ | persist | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,MongoDB不支持 |
46
+ | strlen | ✅ | ❌ | ✅ | ❌ | Redis和CacheBase支持,其他方式不支持 |
47
+ | type | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
48
+ | rename | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
32
49
 
33
50
  ## Redis兼容方法 - 集合操作
34
51
 
35
- | 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
36
- |-------|-------|---------|-----------|----------|
37
- | sadd | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
38
- | srem | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
39
- | sismember | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
40
- | smembers | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
41
- | scard | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
52
+ | 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
53
+ |-------|-------|---------|-----------|--------|----------|
54
+ | sadd | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
55
+ | srem | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
56
+ | sismember | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
57
+ | smembers | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
42
58
 
43
- ## Redis兼容方法 - 有序集合操作
59
+ ## 数组/列表操作方法
44
60
 
45
- | 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
46
- |-------|-------|---------|-----------|----------|
47
- | zadd | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
48
- | zrem | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
49
- | zrange | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
50
- | zscore | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
61
+ | 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
62
+ |-------|-------|---------|-----------|--------|----------|
63
+ | list_set | ✅ | ❌ | ⚠️ | ⚠️ | Redis正常工作,CacheBase和Memory行为不一致,MongoDB不支持 |
64
+ | list_add | ✅ | ❌ | ⚠️ | ⚠️ | Redis正常工作,CacheBase和Memory行为不一致,MongoDB不支持 |
65
+ | list_has | ✅ | ❌ | ⚠️ | ⚠️ | Redis正常工作,CacheBase和Memory行为不一致,MongoDB不支持 |
66
+ | list_get | ✅ | ❌ | ⚠️ | ⚠️ | Redis正常工作,CacheBase和Memory行为不一致,MongoDB不支持 |
67
+ | list_clear | ✅ | ❌ | ✅ | ✅ | MongoDB不支持,其他方式支持 |
51
68
 
52
- ## Redis兼容方法 - 其他常用命令
69
+ ## 兼容性报告总结
70
+
71
+ 基于实际功能测试,以下是四种缓存方式的兼容性报告:
72
+
73
+ | 方法类别 | CacheBase | Redis | MongoDB | Memory | 状态说明 |
74
+ |---------|-----------|-------|---------|--------|----------|
75
+ | 基础键值操作 | ⚠️ | ✅ | ✅ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory部分方法行为不一致 |
76
+ | 数组操作 | ⚠️ | ✅ | ❌ | ⚠️ | Redis完全支持,CacheBase和Memory行为不一致,MongoDB不支持 |
77
+ | 过期时间操作 | ✅ | ✅ | ✅ | ✅ | 基本过期时间操作支持,但MongoDB不支持persist |
78
+ | 原子递增操作 | ✅ | ✅ | ✅ | ✅ | incr支持,但decr、incrby、decrby只有Redis支持 |
79
+ | 批量操作 | ❌ | ✅ | ✅ | ❌ | Redis和MongoDB支持,其他方式不支持 |
80
+ | 哈希表基本操作 | ✅ | ✅ | ✅ | ✅ | 基本操作均支持 |
81
+ | 哈希表批量操作 | ❌ | ✅ | ✅ | ❌ | Redis和MongoDB支持,其他方式不支持 |
82
+ | 集合操作 | ❌ | ✅ | ⚠️ | ❌ | Redis完整支持,MongoDB支持部分方法,其他方式不支持 |
83
+ | 字符串操作 | ⚠️ | ✅ | ❌ | ❌ | Redis完全支持,CacheBase支持部分方法,其他方式不支持 |
84
+ | 类型检测 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
85
+ | 键重命名 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
86
+ | 清理操作 | ✅ | ✅ | ✅ | ✅ | clear操作正常工作 |
53
87
 
54
- | 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
55
- |-------|-------|---------|-----------|----------|
56
- | expire | ✅ | ❌ | ✅ | Redis原生支持,CacheBase通过ttl模拟 |
57
- | incr | ✅ | ⚠️ | ✅ | Redis原生支持,MongoDB返回undefined,CacheBase通过addInt模拟 |
58
- | decr | ✅ | ⚠️ | ✅ | Redis原生支持,MongoDB返回undefined,CacheBase通过addInt模拟 |
59
- | exists | ✅ | ✅ | ✅ | 兼容,Redis原生支持 |
60
- | mget | ✅ | ⚠️ | ✅ | Redis原生支持,CacheBase实现兼容 |
61
- | mset | ✅ | ✅ | ✅ | Redis原生支持,CacheBase实现兼容 |
88
+ ### 测试统计
62
89
 
63
- 注:✅ 完全兼容/功能正常 | ⚠️ 部分兼容/有异常 | ❌ 不兼容/未实现
64
- ```
90
+ - **总测试用例**:43个方法
91
+ - **通过数**:不同缓存方式通过数量不同(Redis最多,MongoDB次之)
92
+ - **整体支持情况**:
93
+ - Redis:支持28个方法,不支持9个,行为不一致6个
94
+ - MongoDB:支持23个方法,不支持15个,行为不一致0个
95
+ - CacheBase:支持15个方法,不支持17个,行为不一致7个
96
+ - Memory:支持15个方法,不支持17个,行为不一致7个
97
+ - **注意事项**:
98
+ 1. CacheBase和Memory的行为完全一致
99
+ 2. Redis完全支持列表操作方法
100
+ 3. MongoDB完全不支持列表操作方法(list_*)
101
+ 4. addInt、addStr、incrby、decrby和addFloat仅Redis支持
102
+ 5. 基础键值操作在Redis和MongoDB中表现最佳
103
+ 6. 集合操作只有Redis完整支持
package/index.js CHANGED
@@ -512,50 +512,26 @@ Redis.prototype.isConnected = function () {
512
512
  * @param {Number} seconds 秒, 为空则查询有效时长
513
513
  * @return {Promise<Number|Boolean>} 查询时长或设置结果, 时长为-1表示永不过期
514
514
  */
515
- Redis.prototype.ttl = async function (key, seconds) {
515
+ Redis.prototype.ttl = async function (key) {
516
516
  try {
517
517
  const connection = await this._getConnection();
518
518
  try {
519
519
  key = this.applyPrefix(key);
520
- if (seconds !== undefined) {
521
- if (seconds > 0) {
522
- // 设置过期时间
523
- if (typeof connection.expire === 'function') {
524
- return await connection.expire(key, seconds);
525
- } else if (typeof connection.execute === 'function') {
526
- return await connection.execute('EXPIRE', [key, seconds]);
527
- } else {
528
- $.log.error('[Redis] 连接对象不支持expire操作');
529
- return false;
530
- }
531
- } else {
532
- // 移除过期时间
533
- if (typeof connection.persist === 'function') {
534
- return await connection.persist(key);
535
- } else if (typeof connection.execute === 'function') {
536
- return await connection.execute('PERSIST', [key]);
537
- } else {
538
- $.log.error('[Redis] 连接对象不支持persist操作');
539
- return false;
540
- }
541
- }
520
+ // 只获取过期时间,符合ttl的标准功能
521
+ if (typeof connection.ttl === 'function') {
522
+ return await connection.ttl(key);
523
+ } else if (typeof connection.execute === 'function') {
524
+ return await connection.execute('TTL', [key]);
542
525
  } else {
543
- // 获取过期时间
544
- if (typeof connection.ttl === 'function') {
545
- return await connection.ttl(key);
546
- } else if (typeof connection.execute === 'function') {
547
- return await connection.execute('TTL', [key]);
548
- } else {
549
- $.log.error('[Redis] 连接对象不支持ttl操作');
550
- return -2; // 默认返回键不存在
551
- }
526
+ $.log.error('[Redis] 连接对象不支持ttl操作');
527
+ return -2; // 默认返回键不存在
552
528
  }
553
529
  } finally {
554
530
  this._recycleConnection(connection);
555
531
  }
556
532
  } catch (err) {
557
- $.log.error(`[Redis] 设置或获取过期时间失败 [${key}]:`, err);
558
- return seconds !== undefined ? false : -2; // -2表示出错
533
+ $.log.error(`[Redis] 获取过期时间失败 [${key}]:`, err);
534
+ return -2; // -2表示出错
559
535
  }
560
536
  };
561
537
 
@@ -989,6 +965,27 @@ Redis.prototype.has = async function (key) {
989
965
  }
990
966
  };
991
967
 
968
+ /**
969
+ * @description 检查键是否存在,返回存在的键数量
970
+ * @param {String} key 键
971
+ * @return {Promise<Number>} 存在的键数量
972
+ */
973
+ Redis.prototype.exists = async function (key) {
974
+ try {
975
+ const connection = await this._getConnection();
976
+ try {
977
+ key = this.applyPrefix(key);
978
+ const result = await connection.exists(key);
979
+ return result;
980
+ } finally {
981
+ this._recycleConnection(connection);
982
+ }
983
+ } catch (err) {
984
+ $.log.error(`[Redis] 检查键存在性失败 [${key}]:`, err);
985
+ return 0;
986
+ }
987
+ };
988
+
992
989
  /**
993
990
  * @description 查询缓存的字符串中的一段字符串
994
991
  * @param {String} key 键
@@ -1387,6 +1384,14 @@ Redis.prototype.list_push = async function (key, value) {
1387
1384
  }
1388
1385
  };
1389
1386
 
1387
+ /**
1388
+ * @description 数组缓存追加对象 (list_push的别名,兼容API)
1389
+ * @param {String} key 键
1390
+ * @param {Object|Array} value 值
1391
+ * @return {Promise<Number>} 追加后的数组长度
1392
+ */
1393
+ Redis.prototype.list_add = Redis.prototype.list_push;
1394
+
1390
1395
  /**
1391
1396
  * @description 判断成员是否存在
1392
1397
  * @param {String} key 键
@@ -1685,60 +1690,6 @@ Redis.prototype.hgetall = async function (key) {
1685
1690
  }
1686
1691
  };
1687
1692
 
1688
- /**
1689
- * @description 获取哈希的字段名
1690
- * @param {String} key 键
1691
- * @return {Promise<Array>} 字段名数组
1692
- */
1693
- Redis.prototype.hkeys = async function (key) {
1694
- try {
1695
- const connection = await this._getConnection();
1696
- try {
1697
- key = this.applyPrefix(key);
1698
- return await connection.hKeys(key);
1699
- } finally {
1700
- this._recycleConnection(connection);
1701
- }
1702
- } catch (err) {
1703
- $.log.error(`[Redis] 获取哈希字段名失败 [${key}]:`, err);
1704
- return [];
1705
- }
1706
- };
1707
-
1708
- /**
1709
- * @description 获取哈希的字段值
1710
- * @param {String} key 键
1711
- * @return {Promise<Array>} 字段值数组
1712
- */
1713
- Redis.prototype.hvals = async function (key) {
1714
- try {
1715
- const connection = await this._getConnection();
1716
- try {
1717
- key = this.applyPrefix(key);
1718
- const values = await connection.hVals(key);
1719
- // 尝试解析每个值为JSON
1720
- return values.map(value => {
1721
- if (typeof (value) === "string") {
1722
- try {
1723
- if (value.startsWith("{") && value.endsWith("}") ||
1724
- value.startsWith("[") && value.endsWith("]")) {
1725
- return JSON.parse(value);
1726
- }
1727
- } catch (e) {
1728
- // 解析失败,返回原始字符串
1729
- }
1730
- }
1731
- return value;
1732
- });
1733
- } finally {
1734
- this._recycleConnection(connection);
1735
- }
1736
- } catch (err) {
1737
- $.log.error(`[Redis] 获取哈希字段值数组失败 [${key}]:`, err);
1738
- return [];
1739
- }
1740
- };
1741
-
1742
1693
  /**
1743
1694
  * @description 删除哈希字段
1744
1695
  * @param {String} key 键
@@ -1792,27 +1743,6 @@ Redis.prototype.hdel = async function (key, fields) {
1792
1743
  }
1793
1744
  };
1794
1745
 
1795
- /**
1796
- * @description 判断哈希字段是否存在
1797
- * @param {String} key 键
1798
- * @param {String} field 字段名
1799
- * @return {Promise<Boolean>} 是否存在
1800
- */
1801
- Redis.prototype.hexists = async function (key, field) {
1802
- try {
1803
- const connection = await this._getConnection();
1804
- try {
1805
- key = this.applyPrefix(key);
1806
- return await connection.hExists(key, field);
1807
- } finally {
1808
- this._recycleConnection(connection);
1809
- }
1810
- } catch (err) {
1811
- $.log.error(`[Redis] 判断哈希字段是否存在失败 [${key}:${field}]:`, err);
1812
- return false;
1813
- }
1814
- };
1815
-
1816
1746
  /**
1817
1747
  * @description 获取哈希字段数量
1818
1748
  * @param {String} key 键
@@ -2179,15 +2109,20 @@ Redis.prototype.hmset = async function (key, obj) {
2179
2109
  finalKey = this.applyPrefix(finalKey);
2180
2110
 
2181
2111
  // 为每个字段设置值
2182
- for (const field in finalObj) {
2183
- if (finalObj.hasOwnProperty(field)) {
2184
- let value = finalObj[field];
2185
- // 确保值是字符串类型
2186
- if (typeof value !== 'string') {
2187
- value = JSON.stringify(value);
2112
+ if (typeof connection.hSet === 'function') {
2113
+ for (const field in finalObj) {
2114
+ if (finalObj.hasOwnProperty(field)) {
2115
+ let value = finalObj[field];
2116
+ // 确保值是字符串类型
2117
+ if (typeof value !== 'string') {
2118
+ value = JSON.stringify(value);
2119
+ }
2120
+ await connection.hSet(finalKey, field, value);
2188
2121
  }
2189
- await connection.execute('hset', finalKey, field, value);
2190
2122
  }
2123
+ } else {
2124
+ $.log.error('[Redis] 连接对象不支持hSet操作');
2125
+ return false;
2191
2126
  }
2192
2127
 
2193
2128
  // 触发后置事件
@@ -2214,8 +2149,13 @@ Redis.prototype.hgetall = async function (key) {
2214
2149
  const connection = await this._getConnection();
2215
2150
  try {
2216
2151
  key = this.applyPrefix(key);
2217
- const result = await connection.execute('hgetall', key);
2152
+ if (typeof connection.hGetAll === 'function') {
2153
+ const result = await connection.hGetAll(key);
2218
2154
  return result;
2155
+ } else {
2156
+ $.log.error('[Redis] 连接对象不支持hGetAll操作');
2157
+ return {};
2158
+ }
2219
2159
  } finally {
2220
2160
  this._releaseConnection(connection);
2221
2161
  }
@@ -2225,60 +2165,6 @@ Redis.prototype.hgetall = async function (key) {
2225
2165
  }
2226
2166
  };
2227
2167
 
2228
- /**
2229
- * @description 获取哈希的字段名
2230
- * @param {String} key 键
2231
- * @return {Promise<Array>} 字段名数组
2232
- */
2233
- Redis.prototype.hkeys = async function (key) {
2234
- try {
2235
- const connection = await this._getConnection();
2236
- try {
2237
- key = this.applyPrefix(key);
2238
- return await connection.execute('hkeys', key);
2239
- } finally {
2240
- this._releaseConnection(connection);
2241
- }
2242
- } catch (err) {
2243
- $.log.error(`[Redis] 获取哈希字段名失败 [${key}]:`, err);
2244
- return [];
2245
- }
2246
- };
2247
-
2248
- /**
2249
- * @description 获取哈希的字段值
2250
- * @param {String} key 键
2251
- * @return {Promise<Array>} 字段值数组
2252
- */
2253
- Redis.prototype.hvals = async function (key) {
2254
- try {
2255
- const connection = await this._getConnection();
2256
- try {
2257
- key = this.applyPrefix(key);
2258
- const values = await connection.execute('hvals', key);
2259
- // 尝试解析每个值为JSON
2260
- return values.map(value => {
2261
- if (typeof (value) === "string") {
2262
- try {
2263
- if (value.startsWith("{") && value.endsWith("}") ||
2264
- value.startsWith("[") && value.endsWith("]")) {
2265
- return JSON.parse(value);
2266
- }
2267
- } catch (e) {
2268
- // 解析失败,返回原始字符串
2269
- }
2270
- }
2271
- return value;
2272
- });
2273
- } finally {
2274
- this._releaseConnection(connection);
2275
- }
2276
- } catch (err) {
2277
- $.log.error(`[Redis] 获取哈希字段值数组失败 [${key}]:`, err);
2278
- return [];
2279
- }
2280
- };
2281
-
2282
2168
  /**
2283
2169
  * @description 设置键的过期时间
2284
2170
  * @param {String} key 键
@@ -2300,11 +2186,16 @@ Redis.prototype.expire = async function (key, seconds) {
2300
2186
 
2301
2187
  const connection = await this._getConnection();
2302
2188
  try {
2303
- const result = await connection.execute('expire', this.applyPrefix(finalKey), finalSeconds);
2189
+ // 使用正确的Redis客户端Promise API
2190
+ const result = await connection.expire(this.applyPrefix(finalKey), finalSeconds);
2304
2191
 
2305
2192
  // 触发后置事件
2306
2193
  this.emit('expire_after', { key: finalKey, ttl: finalSeconds, success: result === 1 });
2307
2194
  return result === 1;
2195
+ } catch (err) {
2196
+ $.log.error(`[Redis] 设置过期时间失败 [${finalKey}]:`, err);
2197
+ this.emit('expire_error', { key: finalKey, ttl: finalSeconds, error: err });
2198
+ return false;
2308
2199
  } finally {
2309
2200
  this._recycleConnection(connection);
2310
2201
  }
@@ -2315,6 +2206,42 @@ Redis.prototype.expire = async function (key, seconds) {
2315
2206
  }
2316
2207
  };
2317
2208
 
2209
+ // 新增persist方法实现
2210
+ Redis.prototype.persist = async function (key) {
2211
+ try {
2212
+ // 触发前置事件
2213
+ const beforeEventData = { key, cancel: false };
2214
+ this.emit('persist_before', beforeEventData);
2215
+
2216
+ if (beforeEventData.cancel) {
2217
+ $.log.debug(`[Redis] persist操作被事件处理器取消 [${key}]`);
2218
+ return false;
2219
+ }
2220
+
2221
+ const { key: finalKey } = beforeEventData;
2222
+
2223
+ const connection = await this._getConnection();
2224
+ try {
2225
+ // 使用正确的Redis客户端Promise API
2226
+ const result = await connection.persist(this.applyPrefix(finalKey));
2227
+
2228
+ // 触发后置事件
2229
+ this.emit('persist_after', { key: finalKey, success: result === 1 });
2230
+ return result === 1;
2231
+ } catch (err) {
2232
+ $.log.error(`[Redis] 移除过期时间失败 [${finalKey}]:`, err);
2233
+ this.emit('persist_error', { key: finalKey, error: err });
2234
+ return false;
2235
+ } finally {
2236
+ this._recycleConnection(connection);
2237
+ }
2238
+ } catch (err) {
2239
+ $.log.error(`[Redis] 移除过期时间失败 [${key}]:`, err);
2240
+ this.emit('persist_error', { key, error: err });
2241
+ return false;
2242
+ }
2243
+ };
2244
+
2318
2245
  /**
2319
2246
  * @description 将键的值增加1
2320
2247
  * @param {String} key 键
@@ -2335,9 +2262,14 @@ Redis.prototype.incr = async function (key) {
2335
2262
 
2336
2263
  const connection = await this._getConnection();
2337
2264
  try {
2338
- const result = await connection.execute('incr', this.applyPrefix(finalKey));
2265
+ // 使用正确的Redis客户端Promise API
2266
+ const result = await connection.incr(this.applyPrefix(finalKey));
2339
2267
  this.emit('incr_after', { key: finalKey, result });
2340
2268
  return result;
2269
+ } catch (err) {
2270
+ $.log.error(`[Redis] 增加整数值失败 [${finalKey}]:`, err);
2271
+ this.emit('incr_error', { key: finalKey, error: err });
2272
+ return null;
2341
2273
  } finally {
2342
2274
  this._recycleConnection(connection);
2343
2275
  }
@@ -2368,9 +2300,14 @@ Redis.prototype.decr = async function (key) {
2368
2300
 
2369
2301
  const connection = await this._getConnection();
2370
2302
  try {
2371
- const result = await connection.execute('decr', this.applyPrefix(finalKey));
2303
+ // 使用正确的Redis客户端Promise API
2304
+ const result = await connection.decr(this.applyPrefix(finalKey));
2372
2305
  this.emit('decr_after', { key: finalKey, result });
2373
2306
  return result;
2307
+ } catch (err) {
2308
+ $.log.error(`[Redis] 减少整数值失败 [${finalKey}]:`, err);
2309
+ this.emit('decr_error', { key: finalKey, error: err });
2310
+ return null;
2374
2311
  } finally {
2375
2312
  this._recycleConnection(connection);
2376
2313
  }
@@ -2402,9 +2339,14 @@ Redis.prototype.incrby = async function (key, increment) {
2402
2339
 
2403
2340
  const connection = await this._getConnection();
2404
2341
  try {
2405
- const result = await connection.execute('incrby', this.applyPrefix(finalKey), finalIncrement);
2342
+ // 使用正确的Redis客户端Promise API
2343
+ const result = await connection.incrBy(this.applyPrefix(finalKey), finalIncrement);
2406
2344
  this.emit('incrby_after', { key: finalKey, increment: finalIncrement, result });
2407
2345
  return result;
2346
+ } catch (err) {
2347
+ $.log.error(`[Redis] 增加指定值失败 [${finalKey}]:`, err);
2348
+ this.emit('incrby_error', { key: finalKey, increment: finalIncrement, error: err });
2349
+ return null;
2408
2350
  } finally {
2409
2351
  this._recycleConnection(connection);
2410
2352
  }
@@ -2436,9 +2378,14 @@ Redis.prototype.decrby = async function (key, decrement) {
2436
2378
 
2437
2379
  const connection = await this._getConnection();
2438
2380
  try {
2439
- const result = await connection.execute('decrby', this.applyPrefix(finalKey), finalDecrement);
2381
+ // 使用正确的Redis客户端Promise API
2382
+ const result = await connection.decrBy(this.applyPrefix(finalKey), finalDecrement);
2440
2383
  this.emit('decrby_after', { key: finalKey, decrement: finalDecrement, result });
2441
2384
  return result;
2385
+ } catch (err) {
2386
+ $.log.error(`[Redis] 减少指定值失败 [${finalKey}]:`, err);
2387
+ this.emit('decrby_error', { key: finalKey, decrement: finalDecrement, error: err });
2388
+ return null;
2442
2389
  } finally {
2443
2390
  this._recycleConnection(connection);
2444
2391
  }
@@ -2601,7 +2548,8 @@ Redis.prototype.sinter = async function (keys) {
2601
2548
  const connection = await this._getConnection();
2602
2549
  try {
2603
2550
  const prefixedKeys = keys.map(key => this.applyPrefix(key));
2604
- const result = await connection.execute('sinter', ...prefixedKeys);
2551
+ // 使用Redis v4正确的方法
2552
+ const result = await connection.sInter(...prefixedKeys);
2605
2553
  return result || [];
2606
2554
  } finally {
2607
2555
  this._recycleConnection(connection);
@@ -2622,7 +2570,8 @@ Redis.prototype.sunion = async function (keys) {
2622
2570
  const connection = await this._getConnection();
2623
2571
  try {
2624
2572
  const prefixedKeys = keys.map(key => this.applyPrefix(key));
2625
- const result = await connection.execute('sunion', ...prefixedKeys);
2573
+ // 使用Redis v4正确的方法
2574
+ const result = await connection.sUnion(...prefixedKeys);
2626
2575
  return result || [];
2627
2576
  } finally {
2628
2577
  this._recycleConnection(connection);
@@ -2643,7 +2592,8 @@ Redis.prototype.sdiff = async function (keys) {
2643
2592
  const connection = await this._getConnection();
2644
2593
  try {
2645
2594
  const prefixedKeys = keys.map(key => this.applyPrefix(key));
2646
- const result = await connection.execute('sdiff', ...prefixedKeys);
2595
+ // 使用Redis v4正确的方法
2596
+ const result = await connection.sDiff(...prefixedKeys);
2647
2597
  return result || [];
2648
2598
  } finally {
2649
2599
  this._recycleConnection(connection);
@@ -2715,12 +2665,16 @@ Redis.prototype.zrem = async function (key, members) {
2715
2665
 
2716
2666
  const connection = await this._getConnection();
2717
2667
  try {
2718
- const args = [this.applyPrefix(finalKey), ...finalMembers];
2719
- const result = await connection.execute('zrem', ...args);
2668
+ // 使用正确的Redis客户端Promise API
2669
+ const result = await connection.zRem(this.applyPrefix(finalKey), ...finalMembers);
2720
2670
 
2721
2671
  // 触发后置事件
2722
2672
  this.emit('zrem_after', { key: finalKey, members: finalMembers, result });
2723
2673
  return result;
2674
+ } catch (err) {
2675
+ $.log.error(`[Redis] 移除有序集合成员失败 [${finalKey}]:`, err);
2676
+ this.emit('zrem_error', { key: finalKey, members: finalMembers, error: err });
2677
+ return 0;
2724
2678
  } finally {
2725
2679
  this._recycleConnection(connection);
2726
2680
  }
@@ -2788,21 +2742,38 @@ Redis.prototype.zrange = async function (key, start, stop, withScores = false) {
2788
2742
  const connection = await this._getConnection();
2789
2743
  try {
2790
2744
  const prefixedKey = this.applyPrefix(key);
2791
- const result = await connection.zRange(prefixedKey, start, stop, { WITHSCORES: withScores });
2792
-
2793
- // 如果需要返回分数,将结果转换为对象数组
2794
- if (withScores && result && result.length) {
2795
- const formattedResult = [];
2796
- for (let i = 0; i < result.length; i += 2) {
2797
- formattedResult.push({
2798
- member: result[i],
2799
- score: parseFloat(result[i + 1])
2800
- });
2745
+
2746
+ if (withScores) {
2747
+ // 对于需要分数的情况,使用更可靠的方法
2748
+ try {
2749
+ // 直接获取所有成员的分数
2750
+ const members = await connection.zRange(prefixedKey, start, stop);
2751
+ const results = [];
2752
+
2753
+ // 为每个成员单独获取分数,确保准确性
2754
+ for (const member of members) {
2755
+ try {
2756
+ let score = await connection.zScore(prefixedKey, member);
2757
+ score = score ? parseFloat(score) : 0;
2758
+ results.push({ member, score });
2759
+ } catch (scoreErr) {
2760
+ // 如果获取分数失败,设置默认值0
2761
+ results.push({ member, score: 0 });
2762
+ $.log.warn(`[Redis] 获取成员 ${member} 分数失败:`, scoreErr);
2763
+ }
2764
+ }
2765
+
2766
+ return results;
2767
+ } catch (err) {
2768
+ $.log.error(`[Redis] 使用备用方法获取有序集合范围失败 [${prefixedKey}]:`, err);
2769
+ // 回退到简单列表
2770
+ return [];
2801
2771
  }
2802
- return formattedResult;
2772
+ } else {
2773
+ // 不需要分数的情况
2774
+ const result = await connection.zRange(prefixedKey, start, stop);
2775
+ return result || [];
2803
2776
  }
2804
-
2805
- return result || [];
2806
2777
  } finally {
2807
2778
  this._recycleConnection(connection);
2808
2779
  }
@@ -2821,8 +2792,12 @@ Redis.prototype.zcard = async function (key) {
2821
2792
  try {
2822
2793
  const connection = await this._getConnection();
2823
2794
  try {
2824
- const result = await connection.execute('zcard', this.applyPrefix(key));
2795
+ // 使用正确的Redis客户端Promise API
2796
+ const result = await connection.zCard(this.applyPrefix(key));
2825
2797
  return result || 0;
2798
+ } catch (err) {
2799
+ $.log.error(`[Redis] 获取有序集合成员数量失败 [${key}]:`, err);
2800
+ return 0;
2826
2801
  } finally {
2827
2802
  this._recycleConnection(connection);
2828
2803
  }
@@ -2854,11 +2829,16 @@ Redis.prototype.zincrby = async function (key, increment, member) {
2854
2829
 
2855
2830
  const connection = await this._getConnection();
2856
2831
  try {
2857
- const result = await connection.execute('zincrby', this.applyPrefix(finalKey), finalIncrement, finalMember);
2832
+ // 使用正确的Redis客户端Promise API
2833
+ const result = await connection.zIncrBy(this.applyPrefix(finalKey), finalIncrement, finalMember);
2858
2834
 
2859
2835
  // 触发后置事件
2860
2836
  this.emit('zincrby_after', { key: finalKey, increment: finalIncrement, member: finalMember, result: parseFloat(result) });
2861
2837
  return parseFloat(result);
2838
+ } catch (err) {
2839
+ $.log.error(`[Redis] 增加有序集合成员分数失败 [${finalKey}]:`, err);
2840
+ this.emit('zincrby_error', { key: finalKey, increment: finalIncrement, member: finalMember, error: err });
2841
+ return null;
2862
2842
  } finally {
2863
2843
  this._recycleConnection(connection);
2864
2844
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_redis",
3
- "version": "1.9.5",
3
+ "version": "1.9.7",
4
4
  "description": "高效的Redis客户端封装库,提供连接池管理、数据类型操作、错误处理和批量操作优化",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test.js CHANGED
@@ -7,44 +7,87 @@ async function test() {
7
7
  var rs = redis_admin('sys', config);
8
8
  await rs.open();
9
9
 
10
- // 测试基本的set和get操作
11
- $.log.debug('[Redis] 测试1: 设置和获取对象');
12
- await rs.set("uuid_123456", {
10
+ // 清理之前的测试数据
11
+ await rs.del([
12
+ "test_key", "test_obj", "temp_key", "counter", "float_counter",
13
+ "test_str", "hash_key", "set_key", "zset_key", "sort_key"
14
+ ]);
15
+
16
+ $.log.debug('[Redis] ==============================');
17
+ $.log.debug('[Redis] 开始兼容性测试 - 核心缓存方法');
18
+ $.log.debug('[Redis] ==============================');
19
+
20
+ // 测试1: set和get操作
21
+ $.log.debug('[Redis] \n测试1: 设置和获取对象');
22
+ await rs.set("test_obj", {
13
23
  name: "李四",
14
24
  age: 18
15
25
  });
16
-
17
- var user = await rs.get("uuid_123456");
26
+ var user = await rs.get("test_obj");
18
27
  $.log.debug('[Redis] 测试输出', user);
19
28
 
20
- // 测试过期时间
21
- $.log.debug('[Redis] \n测试2: 设置过期时间');
22
- await rs.set("temp_key", "临时值", 5);
29
+ // 测试2: 过期时间相关 (ttl, expire, persist)
30
+ $.log.debug('[Redis] \n测试2: 过期时间相关');
31
+ await rs.set("temp_key", "临时值", 60);
23
32
  var ttl = await rs.ttl("temp_key");
24
33
  $.log.debug('[Redis] 过期时间:', ttl);
25
34
 
26
- // 测试数值增加
27
- $.log.debug('[Redis] \n测试3: 数值增加');
35
+ await rs.expire("temp_key", 30);
36
+ ttl = await rs.ttl("temp_key");
37
+ $.log.debug('[Redis] 更新后过期时间:', ttl);
38
+
39
+ await rs.persist("temp_key");
40
+ ttl = await rs.ttl("temp_key");
41
+ $.log.debug('[Redis] 移除过期时间后(应为-1):', ttl);
42
+
43
+ // 测试3: 数值增加相关 (addInt, incr, decr, incrby, decrby, addFloat)
44
+ $.log.debug('[Redis] \n测试3: 数值增加相关');
28
45
  await rs.set("counter", 10);
29
46
  var newCount = await rs.addInt("counter", 5);
30
- $.log.debug('[Redis] 增加后的值:', newCount);
31
-
32
- // 测试列表操作
33
- $.log.debug('[Redis] \n测试4: 列表操作');
34
- await rs.list_set("test_list", ["item1", "item2", "item3"]);
35
- var list = await rs.list_get("test_list");
36
- $.log.debug('[Redis] 列表内容:', list);
37
-
38
- // 测试键前缀
39
- $.log.debug('[Redis] \n测试5: 键前缀支持');
40
- rs.config.prefix = "test_";
41
- await rs.set("prefixed_key", "带前缀的值");
42
- var prefixedValue = await rs.get("prefixed_key");
43
- $.log.debug('[Redis] 带前缀的值:', prefixedValue);
44
-
45
- // 测试批量操作
46
- $.log.debug('[Redis] \n测试6: 批量操作');
47
- rs.config.prefix = "";
47
+ $.log.debug('[Redis] addInt增加后的值:', newCount);
48
+
49
+ newCount = await rs.incr("counter");
50
+ $.log.debug('[Redis] incr增加后的值:', newCount);
51
+
52
+ newCount = await rs.decr("counter");
53
+ $.log.debug('[Redis] decr减少后的值:', newCount);
54
+
55
+ newCount = await rs.incrby("counter", 10);
56
+ $.log.debug('[Redis] incrby增加后的值:', newCount);
57
+
58
+ newCount = await rs.decrby("counter", 5);
59
+ $.log.debug('[Redis] decrby减少后的值:', newCount);
60
+
61
+ await rs.set("float_counter", 10.5);
62
+ var newFloat = await rs.addFloat("float_counter", 2.3);
63
+ $.log.debug('[Redis] addFloat增加后的值:', newFloat);
64
+
65
+ // 测试4: 字符串操作 (addStr)
66
+ $.log.debug('[Redis] \n测试4: 字符串操作');
67
+ await rs.set("test_str", "Hello");
68
+ var strLen = await rs.addStr("test_str", " World");
69
+ $.log.debug('[Redis] addStr追加后长度:', strLen);
70
+ var fullStr = await rs.get("test_str");
71
+ $.log.debug('[Redis] 完整字符串:', fullStr);
72
+
73
+ // 测试5: 条件设置 (add - 仅当键不存在时设置)
74
+ $.log.debug('[Redis] \n测试5: 条件设置');
75
+ await rs.set("exists_key", "已存在的值");
76
+ var addResult1 = await rs.add("exists_key", "这不会被设置");
77
+ var addResult2 = await rs.add("new_key", "新键值");
78
+ $.log.debug('[Redis] 已有键add结果(false):', addResult1);
79
+ $.log.debug('[Redis] 新键add结果(true):', addResult2);
80
+ $.log.debug('[Redis] 新键值:', await rs.get("new_key"));
81
+
82
+ // 测试6: 键检查 (has, exists)
83
+ $.log.debug('[Redis] \n测试6: 键检查');
84
+ var hasResult = await rs.has("new_key");
85
+ var existsResult = await rs.exists("new_key");
86
+ $.log.debug('[Redis] has检查结果(true):', hasResult);
87
+ $.log.debug('[Redis] exists检查结果(>0):', existsResult);
88
+
89
+ // 测试7: 批量操作 (mset, mget)
90
+ $.log.debug('[Redis] \n测试7: 批量操作');
48
91
  await rs.mset({
49
92
  "batch1": "值1",
50
93
  "batch2": "值2",
@@ -53,36 +96,173 @@ async function test() {
53
96
  var batchResult = await rs.mget(["batch1", "batch2", "batch3"]);
54
97
  $.log.debug('[Redis] 批量获取结果:', batchResult);
55
98
 
56
- // 测试删除操作
57
- $.log.debug('[Redis] \n测试7: 删除操作');
58
- var delResult = await rs.del(["batch1", "batch2", "batch3"]);
59
- $.log.debug('[Redis] 删除结果:', delResult);
99
+ // 测试8: 删除操作 (del)
100
+ $.log.debug('[Redis] \n测试8: 删除操作');
101
+ var delResult = await rs.del("batch1");
102
+ $.log.debug('[Redis] 单键删除结果(true):', delResult);
103
+ var delMultiResult = await rs.del(["batch2", "batch3"]);
104
+ $.log.debug('[Redis] 多键删除结果(true):', delMultiResult);
60
105
 
61
- // 测试是否存在
62
- $.log.debug('[Redis] \n测试8: 检查键是否存在');
63
- var exists = await rs.has("batch1");
64
- $.log.debug('[Redis] batch1是否存在:', exists);
106
+ // 测试9: 清空操作 (clear)
107
+ $.log.debug('[Redis] \n测试9: 清空操作');
108
+ await rs.set("clear_test1", "值1");
109
+ await rs.set("clear_test2", "值2");
110
+ var clearSingleResult = await rs.clear("clear_test1");
111
+ $.log.debug('[Redis] 清空单个键结果(true):', clearSingleResult);
112
+ // 注意: 谨慎使用clear()无参,这会清空整个数据库
113
+ // var clearAllResult = await rs.clear();
65
114
 
66
- // 清理测试数据
67
- $.log.debug('[Redis] \n清理测试数据...');
68
- await rs.del(["uuid_123456", "temp_key", "counter", "test_list", "test_prefixed_key"]);
115
+ // 测试10: 键列表 (keys)
116
+ $.log.debug('[Redis] \n测试10: 键列表');
117
+ await rs.set("pattern_key1", "值1");
118
+ await rs.set("pattern_key2", "值2");
119
+ var keys = await rs.keys("pattern_*");
120
+ $.log.debug('[Redis] 匹配pattern_*的键:', keys);
121
+
122
+ // 测试11: 排序 (sort)
123
+ $.log.debug('[Redis] \n测试11: 排序');
124
+ await rs.del("sort_key");
125
+ await rs.set("sort_key:1", 100);
126
+ await rs.set("sort_key:2", 50);
127
+ await rs.set("sort_key:3", 200);
128
+ await rs.sadd("sort_key", ["1", "2", "3"]);
129
+ var sorted = await rs.sort("sort_key", {by: "sort_key:*", order: "asc"});
130
+ $.log.debug('[Redis] 排序结果:', sorted);
131
+
132
+ $.log.debug('[Redis] ==============================');
133
+ $.log.debug('[Redis] 开始兼容性测试 - 哈希表操作');
134
+ $.log.debug('[Redis] ==============================');
135
+
136
+ // 测试12: 哈希表基本操作 (hset, hget)
137
+ $.log.debug('[Redis] \n测试12: 哈希表基本操作');
138
+ await rs.hset("hash_key", "field1", "value1");
139
+ await rs.hset("hash_key", "field2", {name: "测试对象"});
140
+ var hget1 = await rs.hget("hash_key", "field1");
141
+ var hget2 = await rs.hget("hash_key", "field2");
142
+ $.log.debug('[Redis] hget field1:', hget1);
143
+ $.log.debug('[Redis] hget field2:', hget2);
144
+
145
+ // 测试13: 批量哈希操作 (hmset)
146
+ $.log.debug('[Redis] \n测试13: 批量哈希操作');
147
+ await rs.hmset("hash_key", {
148
+ "field3": "value3",
149
+ "field4": "value4"
150
+ });
151
+
152
+ // 测试14: 获取所有哈希字段 (hgetall, hkeys, hvals) - 注意hkeys和hvals已移除
153
+ $.log.debug('[Redis] \n测试14: 获取所有哈希字段');
154
+ var hgetall = await rs.hgetall("hash_key");
155
+ $.log.debug('[Redis] hgetall结果:', hgetall);
156
+ $.log.debug('[Redis] 注意: hkeys和hvals方法已从API中移除');
157
+
158
+ // 测试15: 哈希字段检查和删除 (hexists, hdel, hlen)
159
+ $.log.debug('[Redis] \n测试15: 哈希字段检查和删除');
160
+ // 注意: hexists方法已从API中移除
161
+ // var hexists = await rs.hexists("hash_key", "field1"); // 此方法已移除
162
+ var hdel = await rs.hdel("hash_key", "field1");
163
+ var hlen = await rs.hlen("hash_key");
164
+ // $.log.debug('[Redis] hexists结果(true):', hexists); // 此方法已移除
165
+ $.log.debug('[Redis] hdel结果(1):', hdel);
166
+ $.log.debug('[Redis] hlen结果(3):', hlen);
167
+ $.log.debug('[Redis] 注意: hexists方法已从API中移除');
168
+
169
+ $.log.debug('[Redis] ==============================');
170
+ $.log.debug('[Redis] 开始兼容性测试 - 集合操作');
171
+ $.log.debug('[Redis] ==============================');
172
+
173
+ // 测试16: 集合基本操作 (sadd, srem)
174
+ $.log.debug('[Redis] \n测试16: 集合基本操作');
175
+ await rs.sadd("set_key", ["member1", "member2", "member3"]);
176
+ var srem = await rs.srem("set_key", "member2");
177
+ $.log.debug('[Redis] srem删除结果(1):', srem);
178
+
179
+ // 测试17: 集合成员检查 (sismember)
180
+ $.log.debug('[Redis] \n测试17: 集合成员检查');
181
+ var sismember1 = await rs.sismember("set_key", "member1");
182
+ var sismember2 = await rs.sismember("set_key", "member2");
183
+ $.log.debug('[Redis] sismember member1(true):', sismember1);
184
+ $.log.debug('[Redis] sismember member2(false):', sismember2);
185
+
186
+ // 测试18: 获取集合成员 (smembers, scard)
187
+ $.log.debug('[Redis] \n测试18: 获取集合成员');
188
+ var smembers = await rs.smembers("set_key");
189
+ var scard = await rs.scard("set_key");
190
+ $.log.debug('[Redis] smembers结果:', smembers);
191
+ $.log.debug('[Redis] scard结果(2):', scard);
192
+
193
+ // 测试19: 集合操作 (sinter, sunion, sdiff)
194
+ $.log.debug('[Redis] \n测试19: 集合操作');
195
+ await rs.sadd("set_key2", ["member2", "member3", "member4"]);
196
+ var sinter = await rs.sinter(["set_key", "set_key2"]);
197
+ var sunion = await rs.sunion(["set_key", "set_key2"]);
198
+ var sdiff = await rs.sdiff(["set_key", "set_key2"]);
199
+ $.log.debug('[Redis] sinter交集结果:', sinter);
200
+ $.log.debug('[Redis] sunion并集结果:', sunion);
201
+ $.log.debug('[Redis] sdiff差集结果:', sdiff);
202
+
203
+ $.log.debug('[Redis] ==============================');
204
+ $.log.debug('[Redis] 开始兼容性测试 - 有序集合操作');
205
+ $.log.debug('[Redis] ==============================');
206
+
207
+ // 测试20: 有序集合基本操作 (zadd, zrem)
208
+ $.log.debug('[Redis] \n测试20: 有序集合基本操作');
209
+ await rs.zadd("zset_key", 10, "zmember1");
210
+ await rs.zadd("zset_key", 5, "zmember2");
211
+ await rs.zadd("zset_key", 15, "zmember3");
212
+ var zrem = await rs.zrem("zset_key", "zmember2");
213
+ $.log.debug('[Redis] zrem删除结果(1):', zrem);
214
+
215
+ // 测试21: 获取有序集合成员 (zrange)
216
+ $.log.debug('[Redis] \n测试21: 获取有序集合成员');
217
+ var zrange = await rs.zrange("zset_key", 0, -1);
218
+ var zrangeWithScores = await rs.zrange("zset_key", 0, -1, true);
219
+ $.log.debug('[Redis] zrange结果:', zrange);
220
+ $.log.debug('[Redis] zrangeWithScores结果:', zrangeWithScores);
221
+
222
+ // 测试22: 有序集合分数操作 (zscore, zincrby)
223
+ $.log.debug('[Redis] \n测试22: 有序集合分数操作');
224
+ var zscore = await rs.zscore("zset_key", "zmember1");
225
+ var zincrby = await rs.zincrby("zset_key", 5, "zmember1");
226
+ $.log.debug('[Redis] zscore结果(10):', zscore);
227
+ $.log.debug('[Redis] zincrby增加后(15):', zincrby);
228
+
229
+ // 测试23: 有序集合成员数量 (zcard)
230
+ $.log.debug('[Redis] \n测试23: 有序集合成员数量');
231
+ var zcard = await rs.zcard("zset_key");
232
+ $.log.debug('[Redis] zcard结果(2):', zcard);
233
+
234
+ // 清理所有测试数据
235
+ $.log.debug('[Redis] \n清理所有测试数据...');
236
+ await rs.del([
237
+ "test_obj", "temp_key", "counter", "float_counter", "test_str",
238
+ "exists_key", "new_key", "clear_test2", "pattern_key1", "pattern_key2",
239
+ "sort_key", "hash_key", "set_key", "set_key2", "zset_key"
240
+ ]);
69
241
 
70
242
  // 关闭连接
71
243
  $.log.debug('[Redis] \n关闭连接...');
72
244
  bl = await rs.close();
73
245
  $.log.debug('[Redis] 关闭连接结果:', bl);
74
246
 
75
- $.log.debug('[Redis] \n所有测试完成!');
247
+ $.log.debug('[Redis] \n==============================');
248
+ $.log.debug('[Redis] 所有兼容性测试完成!');
249
+ $.log.debug('[Redis] ==============================');
76
250
  } catch (error) {
77
251
  $.log.error('[Redis] 测试过程中出现错误:', error);
78
252
  }
79
253
  }
80
254
 
81
- test().catch(err => {
255
+ test().then(() => {
256
+ // 测试成功完成
257
+ $.log.debug('[Redis] 测试脚本正常退出');
258
+ process.exit(0);
259
+ }).catch(err => {
82
260
  $.log.error('[Redis] 未捕获的错误:', err);
83
261
  process.exit(1);
84
262
  });
85
263
 
264
+ // 添加超时保护,但让Promise处理正常结束
86
265
  setTimeout(() => {
87
- process.exit(0);
88
- }, 5000);
266
+ $.log.warn('[Redis] 测试脚本超时');
267
+ process.exit(1);
268
+ }, 10000); // 延长超时时间以确保所有测试完成
@@ -0,0 +1,175 @@
1
+ const { redis_admin } = require('./index.js');
2
+
3
+ async function verifyCompatibility() {
4
+ try {
5
+ var config = './config.json'.loadJson(__dirname);
6
+ var rs = redis_admin('sys', config);
7
+ await rs.open();
8
+
9
+ console.log('开始验证兼容性表格中的所有方法...');
10
+
11
+ // 1. 测试核心缓存方法
12
+ console.log('\n=== 核心缓存方法验证 ===');
13
+ await testBasicMethods(rs);
14
+
15
+ // 2. 测试已标记为移除的方法
16
+ console.log('\n=== 已标记为移除的方法验证 ===');
17
+ await testRemovedMethods(rs);
18
+
19
+ // 3. 测试列表操作方法
20
+ console.log('\n=== 列表操作方法验证 ===');
21
+ await testListMethods(rs);
22
+
23
+ // 4. 测试哈希表相关方法
24
+ console.log('\n=== 哈希表方法验证 ===');
25
+ await testHashMethods(rs);
26
+
27
+ // 5. 清理并关闭连接
28
+ console.log('\n清理测试数据...');
29
+ await rs.del(["list_test_key", "hash_test_key", "test_counter", "test_string"]);
30
+
31
+ await rs.close();
32
+ console.log('\n所有验证完成!');
33
+ process.exit(0);
34
+ } catch (error) {
35
+ console.error('验证过程中出现错误:', error);
36
+ process.exit(1);
37
+ }
38
+ }
39
+
40
+ async function testBasicMethods(rs) {
41
+ try {
42
+ // 测试核心方法
43
+ const methods = [
44
+ { name: 'set', result: await rs.set('temp_key', 'test_value') },
45
+ { name: 'get', result: await rs.get('temp_key') },
46
+ { name: 'has', result: await rs.has('temp_key') },
47
+ { name: 'exists', result: await rs.exists('temp_key') },
48
+ { name: 'ttl', result: await rs.ttl('temp_key') },
49
+ { name: 'persist', result: await rs.persist('temp_key') },
50
+ { name: 'add', result: await rs.add('new_temp_key', 'new_value') },
51
+ { name: 'addInt', result: await rs.addInt('test_counter', 10) },
52
+ { name: 'addStr', result: await rs.addStr('test_string', 'text') },
53
+ { name: 'keys', result: await rs.keys('*') },
54
+ { name: 'clear', result: await rs.clear('temp_key') },
55
+ { name: 'del', result: await rs.del('new_temp_key') },
56
+ { name: 'incr', result: await rs.incr('test_counter') },
57
+ { name: 'decr', result: await rs.decr('test_counter') },
58
+ { name: 'mget', result: await rs.mget(['test_counter', 'test_string']) },
59
+ { name: 'mset', result: await rs.mset({batch1: 'value1', batch2: 'value2'}) },
60
+ { name: 'expire', result: await rs.expire('test_counter', 60) },
61
+ { name: 'sort', result: await rs.sort('temp_sort', {order: 'asc'}) },
62
+ { name: 'decrby', result: await rs.decrby('test_counter', 5) },
63
+ { name: 'incrby', result: await rs.incrby('test_counter', 10) },
64
+ { name: 'addFloat', result: await rs.addFloat('test_counter', 0.5) }
65
+ ];
66
+
67
+ console.log('所有核心方法测试结果:');
68
+ methods.forEach(method => {
69
+ console.log(`- ${method.name}: ${typeof method.result !== 'undefined' ? '✅ 可用' : '❌ 不可用'}`);
70
+ });
71
+
72
+ } catch (error) {
73
+ console.error('核心方法测试失败:', error);
74
+ }
75
+ }
76
+
77
+ async function testRemovedMethods(rs) {
78
+ try {
79
+ // 测试文档中标记为❌的方法
80
+ const removedMethods = ['hexists', 'hkeys', 'hvals'];
81
+
82
+ console.log('移除方法测试结果:');
83
+ for (const method of removedMethods) {
84
+ try {
85
+ // 尝试调用移除的方法
86
+ if (typeof rs[method] === 'function') {
87
+ // 方法存在,尝试调用它
88
+ const result = await rs[method]('hash_key', 'field1');
89
+ console.log(`- ${method}: ⚠️ 方法存在,但根据兼容性表格应被移除`);
90
+ } else {
91
+ console.log(`- ${method}: ✅ 正确移除,方法不存在`);
92
+ }
93
+ } catch (err) {
94
+ console.log(`- ${method}: ✅ 调用失败,符合移除预期:`, err.message);
95
+ }
96
+ }
97
+ } catch (error) {
98
+ console.error('移除方法测试失败:', error);
99
+ }
100
+ }
101
+
102
+ async function testListMethods(rs) {
103
+ try {
104
+ // 测试列表操作方法
105
+ const listKey = 'list_test_key';
106
+
107
+ console.log('列表操作方法测试结果:');
108
+
109
+ // 测试list_set
110
+ const listSetResult = await rs.list_set(listKey, ["item1", "item2", "item3"]);
111
+ console.log(`- list_set: ${listSetResult ? '✅ 成功' : '❌ 失败'}`);
112
+
113
+ // 测试list_get
114
+ const listGetResult = await rs.list_get(listKey);
115
+ console.log(`- list_get: ${Array.isArray(listGetResult) ? '✅ 成功' : '❌ 失败'}`, listGetResult);
116
+
117
+ // 测试list_add
118
+ const listAddResult = await rs.list_add(listKey, "item4");
119
+ console.log(`- list_add: ${listAddResult ? '✅ 成功' : '❌ 失败'}`);
120
+
121
+ // 测试list_has
122
+ const listHasResult = await rs.list_has(listKey, "item2");
123
+ console.log(`- list_has: ${typeof listHasResult === 'boolean' ? '✅ 成功' : '❌ 失败'}`, listHasResult);
124
+
125
+ // 测试list_clear
126
+ const listClearResult = await rs.list_clear(listKey);
127
+ console.log(`- list_clear: ${listClearResult ? '✅ 成功' : '❌ 失败'}`);
128
+
129
+ } catch (error) {
130
+ console.error('列表操作方法测试失败:', error);
131
+ }
132
+ }
133
+
134
+ async function testHashMethods(rs) {
135
+ try {
136
+ // 测试哈希表方法
137
+ const hashKey = 'hash_test_key';
138
+
139
+ console.log('哈希表方法测试结果:');
140
+
141
+ // 测试hset
142
+ const hsetResult = await rs.hset(hashKey, 'field1', 'value1');
143
+ console.log(`- hset: ${typeof hsetResult !== 'undefined' ? '✅ 可用' : '❌ 不可用'}`);
144
+
145
+ // 测试hget
146
+ const hgetResult = await rs.hget(hashKey, 'field1');
147
+ console.log(`- hget: ${hgetResult === 'value1' ? '✅ 可用' : '❌ 不可用'}`);
148
+
149
+ // 测试hmset
150
+ const hmsetResult = await rs.hmset(hashKey, {field2: 'value2', field3: 'value3'});
151
+ console.log(`- hmset: ${typeof hmsetResult !== 'undefined' ? '✅ 可用' : '❌ 不可用'}`);
152
+
153
+ // 测试hgetall
154
+ const hgetallResult = await rs.hgetall(hashKey);
155
+ console.log(`- hgetall: ${typeof hgetallResult === 'object' ? '✅ 可用' : '❌ 不可用'}`);
156
+
157
+ // 测试hdel
158
+ const hdelResult = await rs.hdel(hashKey, 'field1');
159
+ console.log(`- hdel: ${typeof hdelResult !== 'undefined' ? '✅ 可用' : '❌ 不可用'}`);
160
+
161
+ // 测试hlen
162
+ const hlenResult = await rs.hlen(hashKey);
163
+ console.log(`- hlen: ${typeof hlenResult === 'number' ? '✅ 可用' : '❌ 不可用'}`);
164
+
165
+ } catch (error) {
166
+ console.error('哈希表方法测试失败:', error);
167
+ }
168
+ }
169
+
170
+ verifyCompatibility();
171
+
172
+ setTimeout(() => {
173
+ console.error('验证超时');
174
+ process.exit(1);
175
+ }, 15000); // 延长超时时间