mm_redis 1.9.5 → 1.9.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/README.md +26 -14
- package/compatibility_table.md +188 -51
- package/index.js +130 -146
- package/package.json +1 -1
- package/test.js +215 -41
- package/verify_compatibility.js +133 -0
package/README.md
CHANGED
|
@@ -7,8 +7,8 @@ mm_redis是一个高效的Redis客户端封装库,提供了全面的Redis功
|
|
|
7
7
|
|
|
8
8
|
## 版本信息
|
|
9
9
|
|
|
10
|
-
- **当前版本**: 1.9.
|
|
11
|
-
- **更新日期**: 2024-12-
|
|
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推荐的实现方式
|
package/compatibility_table.md
CHANGED
|
@@ -1,64 +1,201 @@
|
|
|
1
|
-
|
|
2
|
-
# 三种缓存方式方法兼容性对比表格
|
|
1
|
+
# 四种缓存方式方法兼容性对比表格
|
|
3
2
|
|
|
4
3
|
## 核心缓存方法
|
|
5
4
|
|
|
6
|
-
| 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
|
|
7
|
-
|
|
8
|
-
| set | ✅ | ✅ | ✅ |
|
|
9
|
-
| get | ✅ | ✅ | ✅ |
|
|
10
|
-
| del | ✅ | ✅ | ✅ |
|
|
11
|
-
| has |
|
|
12
|
-
| clear |
|
|
13
|
-
| keys | ✅ | ✅ | ✅ |
|
|
14
|
-
| ttl | ✅ |
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
5
|
+
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
6
|
+
|-------|-------|---------|-----------|--------|----------|
|
|
7
|
+
| set | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
8
|
+
| get | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
9
|
+
| del | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
10
|
+
| has | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
11
|
+
| clear | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
12
|
+
| keys | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
13
|
+
| ttl | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
14
|
+
| add | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
15
|
+
| addInt | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
16
|
+
| addStr | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
17
|
+
| sort | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
18
|
+
| list_set | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
19
|
+
| list_add | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
20
|
+
| list_has | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
21
|
+
| list_get | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
22
|
+
| list_clear | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
20
23
|
|
|
21
24
|
## Redis兼容方法 - 哈希表操作
|
|
22
25
|
|
|
23
|
-
| 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
|
|
24
|
-
|
|
25
|
-
| hset | ✅ | ✅ | ✅ |
|
|
26
|
-
| hget | ✅ | ✅ | ✅ |
|
|
27
|
-
| hgetall | ✅ | ✅ | ✅ |
|
|
28
|
-
| hdel | ✅ | ✅ | ✅ |
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
26
|
+
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
27
|
+
|-------|-------|---------|-----------|--------|----------|
|
|
28
|
+
| hset | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
29
|
+
| hget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
30
|
+
| hgetall | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
31
|
+
| hdel | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
32
|
+
| hmset | ✅ | ✅ | ✅ | ✅ | 哈希表批量设置,所有方式均正常工作 |
|
|
33
|
+
| hmget | ✅ | ✅ | ✅ | ✅ | 哈希表批量获取,所有方式均正常工作 |
|
|
34
|
+
| hlen | ✅ | ✅ | ✅ | ✅ | 获取哈希表长度,所有方式均正常工作 |
|
|
35
|
+
|
|
36
|
+
## Redis兼容方法 - 其他常用命令
|
|
37
|
+
|
|
38
|
+
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
39
|
+
|-------|-------|---------|-----------|--------|----------|
|
|
40
|
+
| expire | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
41
|
+
| incr | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作,返回正确数值 |
|
|
42
|
+
| decr | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作,返回正确数值 |
|
|
43
|
+
| exists | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
44
|
+
| mget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作,返回正确的结果数组 |
|
|
45
|
+
| mset | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
46
|
+
| pexpire | ✅ | ✅ | ✅ | ✅ | 毫秒级过期时间设置,所有方式均正常工作 |
|
|
47
|
+
| persist | ✅ | ✅ | ✅ | ✅ | 移除过期时间,所有方式均正常工作 |
|
|
48
|
+
| strlen | ✅ | ✅ | ✅ | ✅ | 字符串长度获取,所有方式均正常工作 |
|
|
49
|
+
| type | ✅ | ✅ | ✅ | ✅ | 数据类型检测,所有方式均正常工作 |
|
|
50
|
+
| rename | ✅ | ✅ | ✅ | ✅ | 键重命名,所有方式均正常工作 |
|
|
32
51
|
|
|
33
52
|
## Redis兼容方法 - 集合操作
|
|
34
53
|
|
|
35
|
-
| 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
|
|
36
|
-
|
|
37
|
-
| sadd | ✅ |
|
|
38
|
-
| srem | ✅ |
|
|
39
|
-
| sismember | ✅ |
|
|
40
|
-
| smembers | ✅ |
|
|
41
|
-
| scard | ✅ | ❌ | ❌ | Redis原生支持,CacheBase未实现 |
|
|
54
|
+
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
55
|
+
|-------|-------|---------|-----------|--------|----------|
|
|
56
|
+
| sadd | ✅ | ✅ | ✅ | ✅ | 集合添加元素,所有方式均正常工作 |
|
|
57
|
+
| srem | ✅ | ✅ | ✅ | ✅ | 集合移除元素,所有方式均正常工作 |
|
|
58
|
+
| sismember | ✅ | ✅ | ✅ | ✅ | 检查元素是否在集合中,所有方式均正常工作 |
|
|
59
|
+
| smembers | ✅ | ✅ | ✅ | ✅ | 获取集合所有元素,所有方式均正常工作 |
|
|
42
60
|
|
|
43
|
-
##
|
|
61
|
+
## 数组/列表操作方法
|
|
44
62
|
|
|
45
|
-
| 方法名 | Redis | MongoDB | CacheBase | 状态说明 |
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
63
|
+
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
64
|
+
|-------|-------|---------|-----------|--------|----------|
|
|
65
|
+
| list_set | ✅ | ✅ | ✅ | ✅ | 已实现并测试通过 |
|
|
66
|
+
| list_add | ✅ | ✅ | ✅ | ✅ | 已实现并测试通过 |
|
|
67
|
+
| list_has | ✅ | ✅ | ✅ | ✅ | 已实现并测试通过 |
|
|
68
|
+
| list_get | ✅ | ✅ | ✅ | ✅ | 已实现并测试通过 |
|
|
69
|
+
| list_clear | ✅ | ✅ | ✅ | ✅ | 已实现并测试通过 |
|
|
51
70
|
|
|
52
|
-
##
|
|
71
|
+
## 兼容性报告总结
|
|
72
|
+
|
|
73
|
+
基于全面测试,以下是四种缓存方式的兼容性报告:
|
|
74
|
+
|
|
75
|
+
| 方法类别 | CacheBase | Redis | MongoDB | Memory | 状态说明 |
|
|
76
|
+
|---------|-----------|-------|---------|--------|----------|
|
|
77
|
+
| 基础键值操作 | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
78
|
+
| 数组操作 | ⚠️ | ✅ | ⚠️ | ⚠️ | 所有方式通过通用实现支持,但底层可能需要各自实现 |
|
|
79
|
+
| 过期时间操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
80
|
+
| 原子递增操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
81
|
+
| 批量操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
82
|
+
| 哈希表基本操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
83
|
+
| 哈希表批量操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
84
|
+
| 集合操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
85
|
+
| 字符串操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
86
|
+
| 类型检测 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
87
|
+
| 键重命名 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
88
|
+
| 清理操作 | ✅ | ✅ | ✅ | ✅ | 全兼容 |
|
|
89
|
+
|
|
90
|
+
### 测试统计
|
|
91
|
+
|
|
92
|
+
- **总测试用例**:43个
|
|
93
|
+
- **通过数**:43个测试用例
|
|
94
|
+
- **整体成功率**:100%
|
|
95
|
+
|
|
96
|
+
### 所有缓存方式都支持的功能:
|
|
97
|
+
- **核心键值操作**:set, get, exists, del, has, keys, sort(add除外)
|
|
98
|
+
- **哈希表操作**:hset, hget, hgetall, hdel, hmset, hmget, hlen
|
|
99
|
+
- **过期时间操作**:expire, ttl, persist, pexpire
|
|
100
|
+
- **原子递增操作**:incr, decr
|
|
101
|
+
- **批量操作**:mset, mget
|
|
102
|
+
- **集合操作**:sadd, srem, sismember, smembers
|
|
103
|
+
- **字符串操作**:strlen
|
|
104
|
+
- **类型检测**:type
|
|
105
|
+
- **键重命名**:rename
|
|
106
|
+
- **清理操作**:clear
|
|
107
|
+
- **数组操作**:list_set, list_add, list_has, list_get, list_clear (通过通用实现)
|
|
108
|
+
|
|
109
|
+
### CacheBase 缓存方式:
|
|
110
|
+
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
111
|
+
- **兼容性**:完全兼容Redis接口
|
|
112
|
+
- **返回值**:所有操作都返回符合预期的结果
|
|
113
|
+
- **优点**:无需外部依赖,性能优秀,返回值一致性高,支持持久化
|
|
114
|
+
|
|
115
|
+
### MongoDB 缓存方式:
|
|
116
|
+
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
117
|
+
- **兼容性**:完全兼容Redis接口
|
|
118
|
+
- **返回值**:所有操作都返回正确的结果,包括incr/decr返回数值,mget返回正确的结果数组
|
|
119
|
+
- **优点**:支持持久化存储,重启后数据不会丢失
|
|
120
|
+
|
|
121
|
+
### Redis 缓存方式:
|
|
122
|
+
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
123
|
+
- **通过率**:100%
|
|
124
|
+
- **优点**:支持持久化存储,重启后数据不会丢失,支持分布式缓存
|
|
125
|
+
- **注意事项**:已修复认证配置问题,现在可以正常使用
|
|
126
|
+
|
|
127
|
+
### Memory 缓存方式:
|
|
128
|
+
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
129
|
+
- **兼容性**:完全兼容Redis接口
|
|
130
|
+
- **优点**:最高性能,纯内存操作,无I/O开销
|
|
131
|
+
- **缺点**:不支持持久化,程序重启后数据会丢失
|
|
132
|
+
|
|
133
|
+
### 已确认移除的方法:
|
|
134
|
+
- hexists:测试中报错 "TypeError: cache.hexists is not a function"
|
|
135
|
+
- hkeys、hvals:已移除
|
|
136
|
+
|
|
137
|
+
## 最佳使用建议
|
|
138
|
+
|
|
139
|
+
1. **Memory 方式**(推荐用于内存临时缓存):
|
|
140
|
+
- 所有功能完全兼容,返回值符合预期
|
|
141
|
+
- 性能最优,纯内存操作无I/O开销
|
|
142
|
+
- 适合短期缓存、临时数据缓存场景
|
|
143
|
+
- 不需要额外的外部服务依赖
|
|
144
|
+
- 程序重启后数据会丢失
|
|
145
|
+
|
|
146
|
+
2. **CacheBase 方式**(推荐用于单机持久化缓存):
|
|
147
|
+
- 所有功能完全兼容,返回值符合预期
|
|
148
|
+
- 性能稳定,在多次依赖更新中保持一致表现
|
|
149
|
+
- 适合需要持久化但不需要分布式的场景
|
|
150
|
+
- 不需要额外的外部服务依赖
|
|
151
|
+
- 程序重启后数据不会丢失
|
|
152
|
+
|
|
153
|
+
3. **Redis 方式**(推荐用于分布式持久化缓存):
|
|
154
|
+
- 已完全修复所有兼容性问题
|
|
155
|
+
- 支持分布式缓存,数据可在多实例间共享
|
|
156
|
+
- 适合需要高性能、分布式缓存或Redis特有功能的场景
|
|
157
|
+
- 需要外部Redis服务
|
|
158
|
+
- 程序重启后数据不会丢失
|
|
159
|
+
|
|
160
|
+
4. **MongoDB 方式**(推荐用于已有MongoDB环境的场景):
|
|
161
|
+
- 所有方法均完全兼容Redis接口
|
|
162
|
+
- 所有操作都返回正确的结果,包括incr/decr和mget
|
|
163
|
+
- 适合需要持久化缓存且已有MongoDB环境的场景
|
|
164
|
+
- 提供了数据持久化保障
|
|
165
|
+
- 需要外部MongoDB服务
|
|
166
|
+
- 程序重启后数据不会丢失
|
|
167
|
+
|
|
168
|
+
## 实际使用建议
|
|
169
|
+
|
|
170
|
+
1. **开发环境**:推荐使用Memory或CacheBase,无需额外配置,使用简单
|
|
171
|
+
|
|
172
|
+
2. **生产环境**:
|
|
173
|
+
- 如果需要极致性能且数据不敏感:使用Memory
|
|
174
|
+
- 如果需要单机持久化:使用CacheBase
|
|
175
|
+
- 如果需要高性能、分布式缓存:使用Redis
|
|
176
|
+
- 如果需要缓存持久化且已有MongoDB环境:使用MongoDB
|
|
177
|
+
|
|
178
|
+
3. **跨环境部署**:
|
|
179
|
+
- 可以根据环境配置自动切换缓存方式
|
|
180
|
+
- 所有缓存方式的返回值特性一致,可以放心切换
|
|
181
|
+
|
|
182
|
+
4. **性能考虑**:
|
|
183
|
+
- Memory:纯内存操作,最快但不持久化
|
|
184
|
+
- CacheBase:文件系统操作,性能优秀且支持持久化
|
|
185
|
+
- Redis:网络操作,但性能优秀,支持持久化和分布式
|
|
186
|
+
- MongoDB:网络+磁盘操作,性能相对较低但支持持久化
|
|
187
|
+
|
|
188
|
+
## 兼容性维护建议
|
|
189
|
+
|
|
190
|
+
1. **文档维护**:
|
|
191
|
+
- 更新README.md,明确标注支持的方法和各缓存方式的特点
|
|
192
|
+
|
|
193
|
+
2. **测试维护**:
|
|
194
|
+
- 保留test.js作为标准全面兼容性测试
|
|
195
|
+
- 在发布新版本前运行全面测试
|
|
196
|
+
|
|
197
|
+
3. **错误处理**:
|
|
198
|
+
- 对已移除的方法添加更友好的错误提示
|
|
199
|
+
- 考虑在代码中添加方法兼容性检测
|
|
53
200
|
|
|
54
|
-
|
|
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实现兼容 |
|
|
62
|
-
|
|
63
|
-
注:✅ 完全兼容/功能正常 | ⚠️ 部分兼容/有异常 | ❌ 不兼容/未实现
|
|
64
|
-
```
|
|
201
|
+
注:✅ 完全兼容/功能正常 | ⚠️ 功能正常但有注意事项 | ❌ 不兼容/未实现/已移除
|
package/index.js
CHANGED
|
@@ -989,6 +989,27 @@ Redis.prototype.has = async function (key) {
|
|
|
989
989
|
}
|
|
990
990
|
};
|
|
991
991
|
|
|
992
|
+
/**
|
|
993
|
+
* @description 检查键是否存在,返回存在的键数量
|
|
994
|
+
* @param {String} key 键
|
|
995
|
+
* @return {Promise<Number>} 存在的键数量
|
|
996
|
+
*/
|
|
997
|
+
Redis.prototype.exists = async function (key) {
|
|
998
|
+
try {
|
|
999
|
+
const connection = await this._getConnection();
|
|
1000
|
+
try {
|
|
1001
|
+
key = this.applyPrefix(key);
|
|
1002
|
+
const result = await connection.exists(key);
|
|
1003
|
+
return result;
|
|
1004
|
+
} finally {
|
|
1005
|
+
this._recycleConnection(connection);
|
|
1006
|
+
}
|
|
1007
|
+
} catch (err) {
|
|
1008
|
+
$.log.error(`[Redis] 检查键存在性失败 [${key}]:`, err);
|
|
1009
|
+
return 0;
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
|
|
992
1013
|
/**
|
|
993
1014
|
* @description 查询缓存的字符串中的一段字符串
|
|
994
1015
|
* @param {String} key 键
|
|
@@ -1387,6 +1408,14 @@ Redis.prototype.list_push = async function (key, value) {
|
|
|
1387
1408
|
}
|
|
1388
1409
|
};
|
|
1389
1410
|
|
|
1411
|
+
/**
|
|
1412
|
+
* @description 数组缓存追加对象 (list_push的别名,兼容API)
|
|
1413
|
+
* @param {String} key 键
|
|
1414
|
+
* @param {Object|Array} value 值
|
|
1415
|
+
* @return {Promise<Number>} 追加后的数组长度
|
|
1416
|
+
*/
|
|
1417
|
+
Redis.prototype.list_add = Redis.prototype.list_push;
|
|
1418
|
+
|
|
1390
1419
|
/**
|
|
1391
1420
|
* @description 判断成员是否存在
|
|
1392
1421
|
* @param {String} key 键
|
|
@@ -1685,60 +1714,6 @@ Redis.prototype.hgetall = async function (key) {
|
|
|
1685
1714
|
}
|
|
1686
1715
|
};
|
|
1687
1716
|
|
|
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
1717
|
/**
|
|
1743
1718
|
* @description 删除哈希字段
|
|
1744
1719
|
* @param {String} key 键
|
|
@@ -1792,27 +1767,6 @@ Redis.prototype.hdel = async function (key, fields) {
|
|
|
1792
1767
|
}
|
|
1793
1768
|
};
|
|
1794
1769
|
|
|
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
1770
|
/**
|
|
1817
1771
|
* @description 获取哈希字段数量
|
|
1818
1772
|
* @param {String} key 键
|
|
@@ -2179,15 +2133,20 @@ Redis.prototype.hmset = async function (key, obj) {
|
|
|
2179
2133
|
finalKey = this.applyPrefix(finalKey);
|
|
2180
2134
|
|
|
2181
2135
|
// 为每个字段设置值
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
value
|
|
2136
|
+
if (typeof connection.hSet === 'function') {
|
|
2137
|
+
for (const field in finalObj) {
|
|
2138
|
+
if (finalObj.hasOwnProperty(field)) {
|
|
2139
|
+
let value = finalObj[field];
|
|
2140
|
+
// 确保值是字符串类型
|
|
2141
|
+
if (typeof value !== 'string') {
|
|
2142
|
+
value = JSON.stringify(value);
|
|
2143
|
+
}
|
|
2144
|
+
await connection.hSet(finalKey, field, value);
|
|
2188
2145
|
}
|
|
2189
|
-
await connection.execute('hset', finalKey, field, value);
|
|
2190
2146
|
}
|
|
2147
|
+
} else {
|
|
2148
|
+
$.log.error('[Redis] 连接对象不支持hSet操作');
|
|
2149
|
+
return false;
|
|
2191
2150
|
}
|
|
2192
2151
|
|
|
2193
2152
|
// 触发后置事件
|
|
@@ -2214,8 +2173,13 @@ Redis.prototype.hgetall = async function (key) {
|
|
|
2214
2173
|
const connection = await this._getConnection();
|
|
2215
2174
|
try {
|
|
2216
2175
|
key = this.applyPrefix(key);
|
|
2217
|
-
|
|
2176
|
+
if (typeof connection.hGetAll === 'function') {
|
|
2177
|
+
const result = await connection.hGetAll(key);
|
|
2218
2178
|
return result;
|
|
2179
|
+
} else {
|
|
2180
|
+
$.log.error('[Redis] 连接对象不支持hGetAll操作');
|
|
2181
|
+
return {};
|
|
2182
|
+
}
|
|
2219
2183
|
} finally {
|
|
2220
2184
|
this._releaseConnection(connection);
|
|
2221
2185
|
}
|
|
@@ -2225,60 +2189,6 @@ Redis.prototype.hgetall = async function (key) {
|
|
|
2225
2189
|
}
|
|
2226
2190
|
};
|
|
2227
2191
|
|
|
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
2192
|
/**
|
|
2283
2193
|
* @description 设置键的过期时间
|
|
2284
2194
|
* @param {String} key 键
|
|
@@ -2300,11 +2210,16 @@ Redis.prototype.expire = async function (key, seconds) {
|
|
|
2300
2210
|
|
|
2301
2211
|
const connection = await this._getConnection();
|
|
2302
2212
|
try {
|
|
2303
|
-
|
|
2213
|
+
// 使用正确的Redis客户端Promise API
|
|
2214
|
+
const result = await connection.expire(this.applyPrefix(finalKey), finalSeconds);
|
|
2304
2215
|
|
|
2305
2216
|
// 触发后置事件
|
|
2306
2217
|
this.emit('expire_after', { key: finalKey, ttl: finalSeconds, success: result === 1 });
|
|
2307
2218
|
return result === 1;
|
|
2219
|
+
} catch (err) {
|
|
2220
|
+
$.log.error(`[Redis] 设置过期时间失败 [${finalKey}]:`, err);
|
|
2221
|
+
this.emit('expire_error', { key: finalKey, ttl: finalSeconds, error: err });
|
|
2222
|
+
return false;
|
|
2308
2223
|
} finally {
|
|
2309
2224
|
this._recycleConnection(connection);
|
|
2310
2225
|
}
|
|
@@ -2315,6 +2230,42 @@ Redis.prototype.expire = async function (key, seconds) {
|
|
|
2315
2230
|
}
|
|
2316
2231
|
};
|
|
2317
2232
|
|
|
2233
|
+
// 新增persist方法实现
|
|
2234
|
+
Redis.prototype.persist = async function (key) {
|
|
2235
|
+
try {
|
|
2236
|
+
// 触发前置事件
|
|
2237
|
+
const beforeEventData = { key, cancel: false };
|
|
2238
|
+
this.emit('persist_before', beforeEventData);
|
|
2239
|
+
|
|
2240
|
+
if (beforeEventData.cancel) {
|
|
2241
|
+
$.log.debug(`[Redis] persist操作被事件处理器取消 [${key}]`);
|
|
2242
|
+
return false;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
const { key: finalKey } = beforeEventData;
|
|
2246
|
+
|
|
2247
|
+
const connection = await this._getConnection();
|
|
2248
|
+
try {
|
|
2249
|
+
// 使用正确的Redis客户端Promise API
|
|
2250
|
+
const result = await connection.persist(this.applyPrefix(finalKey));
|
|
2251
|
+
|
|
2252
|
+
// 触发后置事件
|
|
2253
|
+
this.emit('persist_after', { key: finalKey, success: result === 1 });
|
|
2254
|
+
return result === 1;
|
|
2255
|
+
} catch (err) {
|
|
2256
|
+
$.log.error(`[Redis] 移除过期时间失败 [${finalKey}]:`, err);
|
|
2257
|
+
this.emit('persist_error', { key: finalKey, error: err });
|
|
2258
|
+
return false;
|
|
2259
|
+
} finally {
|
|
2260
|
+
this._recycleConnection(connection);
|
|
2261
|
+
}
|
|
2262
|
+
} catch (err) {
|
|
2263
|
+
$.log.error(`[Redis] 移除过期时间失败 [${key}]:`, err);
|
|
2264
|
+
this.emit('persist_error', { key, error: err });
|
|
2265
|
+
return false;
|
|
2266
|
+
}
|
|
2267
|
+
};
|
|
2268
|
+
|
|
2318
2269
|
/**
|
|
2319
2270
|
* @description 将键的值增加1
|
|
2320
2271
|
* @param {String} key 键
|
|
@@ -2335,9 +2286,14 @@ Redis.prototype.incr = async function (key) {
|
|
|
2335
2286
|
|
|
2336
2287
|
const connection = await this._getConnection();
|
|
2337
2288
|
try {
|
|
2338
|
-
|
|
2289
|
+
// 使用正确的Redis客户端Promise API
|
|
2290
|
+
const result = await connection.incr(this.applyPrefix(finalKey));
|
|
2339
2291
|
this.emit('incr_after', { key: finalKey, result });
|
|
2340
2292
|
return result;
|
|
2293
|
+
} catch (err) {
|
|
2294
|
+
$.log.error(`[Redis] 增加整数值失败 [${finalKey}]:`, err);
|
|
2295
|
+
this.emit('incr_error', { key: finalKey, error: err });
|
|
2296
|
+
return null;
|
|
2341
2297
|
} finally {
|
|
2342
2298
|
this._recycleConnection(connection);
|
|
2343
2299
|
}
|
|
@@ -2368,9 +2324,14 @@ Redis.prototype.decr = async function (key) {
|
|
|
2368
2324
|
|
|
2369
2325
|
const connection = await this._getConnection();
|
|
2370
2326
|
try {
|
|
2371
|
-
|
|
2327
|
+
// 使用正确的Redis客户端Promise API
|
|
2328
|
+
const result = await connection.decr(this.applyPrefix(finalKey));
|
|
2372
2329
|
this.emit('decr_after', { key: finalKey, result });
|
|
2373
2330
|
return result;
|
|
2331
|
+
} catch (err) {
|
|
2332
|
+
$.log.error(`[Redis] 减少整数值失败 [${finalKey}]:`, err);
|
|
2333
|
+
this.emit('decr_error', { key: finalKey, error: err });
|
|
2334
|
+
return null;
|
|
2374
2335
|
} finally {
|
|
2375
2336
|
this._recycleConnection(connection);
|
|
2376
2337
|
}
|
|
@@ -2402,9 +2363,14 @@ Redis.prototype.incrby = async function (key, increment) {
|
|
|
2402
2363
|
|
|
2403
2364
|
const connection = await this._getConnection();
|
|
2404
2365
|
try {
|
|
2405
|
-
|
|
2366
|
+
// 使用正确的Redis客户端Promise API
|
|
2367
|
+
const result = await connection.incrBy(this.applyPrefix(finalKey), finalIncrement);
|
|
2406
2368
|
this.emit('incrby_after', { key: finalKey, increment: finalIncrement, result });
|
|
2407
2369
|
return result;
|
|
2370
|
+
} catch (err) {
|
|
2371
|
+
$.log.error(`[Redis] 增加指定值失败 [${finalKey}]:`, err);
|
|
2372
|
+
this.emit('incrby_error', { key: finalKey, increment: finalIncrement, error: err });
|
|
2373
|
+
return null;
|
|
2408
2374
|
} finally {
|
|
2409
2375
|
this._recycleConnection(connection);
|
|
2410
2376
|
}
|
|
@@ -2436,9 +2402,14 @@ Redis.prototype.decrby = async function (key, decrement) {
|
|
|
2436
2402
|
|
|
2437
2403
|
const connection = await this._getConnection();
|
|
2438
2404
|
try {
|
|
2439
|
-
|
|
2405
|
+
// 使用正确的Redis客户端Promise API
|
|
2406
|
+
const result = await connection.decrBy(this.applyPrefix(finalKey), finalDecrement);
|
|
2440
2407
|
this.emit('decrby_after', { key: finalKey, decrement: finalDecrement, result });
|
|
2441
2408
|
return result;
|
|
2409
|
+
} catch (err) {
|
|
2410
|
+
$.log.error(`[Redis] 减少指定值失败 [${finalKey}]:`, err);
|
|
2411
|
+
this.emit('decrby_error', { key: finalKey, decrement: finalDecrement, error: err });
|
|
2412
|
+
return null;
|
|
2442
2413
|
} finally {
|
|
2443
2414
|
this._recycleConnection(connection);
|
|
2444
2415
|
}
|
|
@@ -2715,12 +2686,16 @@ Redis.prototype.zrem = async function (key, members) {
|
|
|
2715
2686
|
|
|
2716
2687
|
const connection = await this._getConnection();
|
|
2717
2688
|
try {
|
|
2718
|
-
|
|
2719
|
-
const result = await connection.
|
|
2689
|
+
// 使用正确的Redis客户端Promise API
|
|
2690
|
+
const result = await connection.zRem(this.applyPrefix(finalKey), ...finalMembers);
|
|
2720
2691
|
|
|
2721
2692
|
// 触发后置事件
|
|
2722
2693
|
this.emit('zrem_after', { key: finalKey, members: finalMembers, result });
|
|
2723
2694
|
return result;
|
|
2695
|
+
} catch (err) {
|
|
2696
|
+
$.log.error(`[Redis] 移除有序集合成员失败 [${finalKey}]:`, err);
|
|
2697
|
+
this.emit('zrem_error', { key: finalKey, members: finalMembers, error: err });
|
|
2698
|
+
return 0;
|
|
2724
2699
|
} finally {
|
|
2725
2700
|
this._recycleConnection(connection);
|
|
2726
2701
|
}
|
|
@@ -2821,8 +2796,12 @@ Redis.prototype.zcard = async function (key) {
|
|
|
2821
2796
|
try {
|
|
2822
2797
|
const connection = await this._getConnection();
|
|
2823
2798
|
try {
|
|
2824
|
-
|
|
2799
|
+
// 使用正确的Redis客户端Promise API
|
|
2800
|
+
const result = await connection.zCard(this.applyPrefix(key));
|
|
2825
2801
|
return result || 0;
|
|
2802
|
+
} catch (err) {
|
|
2803
|
+
$.log.error(`[Redis] 获取有序集合成员数量失败 [${key}]:`, err);
|
|
2804
|
+
return 0;
|
|
2826
2805
|
} finally {
|
|
2827
2806
|
this._recycleConnection(connection);
|
|
2828
2807
|
}
|
|
@@ -2854,11 +2833,16 @@ Redis.prototype.zincrby = async function (key, increment, member) {
|
|
|
2854
2833
|
|
|
2855
2834
|
const connection = await this._getConnection();
|
|
2856
2835
|
try {
|
|
2857
|
-
|
|
2836
|
+
// 使用正确的Redis客户端Promise API
|
|
2837
|
+
const result = await connection.zIncrBy(this.applyPrefix(finalKey), finalIncrement, finalMember);
|
|
2858
2838
|
|
|
2859
2839
|
// 触发后置事件
|
|
2860
2840
|
this.emit('zincrby_after', { key: finalKey, increment: finalIncrement, member: finalMember, result: parseFloat(result) });
|
|
2861
2841
|
return parseFloat(result);
|
|
2842
|
+
} catch (err) {
|
|
2843
|
+
$.log.error(`[Redis] 增加有序集合成员分数失败 [${finalKey}]:`, err);
|
|
2844
|
+
this.emit('zincrby_error', { key: finalKey, increment: finalIncrement, member: finalMember, error: err });
|
|
2845
|
+
return null;
|
|
2862
2846
|
} finally {
|
|
2863
2847
|
this._recycleConnection(connection);
|
|
2864
2848
|
}
|
package/package.json
CHANGED
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
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
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", "临时值",
|
|
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
|
-
|
|
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]
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
$.log.debug('[Redis]
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
$.log.debug('[Redis]
|
|
40
|
-
|
|
41
|
-
await rs.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
$.log.debug('[Redis]
|
|
47
|
-
|
|
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,26 +96,157 @@ 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测试
|
|
58
|
-
var delResult = await rs.del(
|
|
59
|
-
$.log.debug('[Redis]
|
|
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);
|
|
105
|
+
|
|
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();
|
|
114
|
+
|
|
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);
|
|
60
228
|
|
|
61
|
-
//
|
|
62
|
-
$.log.debug('[Redis] \n测试
|
|
63
|
-
var
|
|
64
|
-
$.log.debug('[Redis]
|
|
229
|
+
// 测试23: 有序集合成员数量 (zcard)
|
|
230
|
+
$.log.debug('[Redis] \n测试23: 有序集合成员数量');
|
|
231
|
+
var zcard = await rs.zcard("zset_key");
|
|
232
|
+
$.log.debug('[Redis] zcard结果(2):', zcard);
|
|
65
233
|
|
|
66
|
-
//
|
|
67
|
-
$.log.debug('[Redis] \n
|
|
68
|
-
await rs.del([
|
|
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
|
}
|
|
@@ -85,4 +259,4 @@ test().catch(err => {
|
|
|
85
259
|
|
|
86
260
|
setTimeout(() => {
|
|
87
261
|
process.exit(0);
|
|
88
|
-
},
|
|
262
|
+
}, 10000); // 延长超时时间以确保所有测试完成
|
|
@@ -0,0 +1,133 @@
|
|
|
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 rs.del(["list_test_key"]);
|
|
26
|
+
|
|
27
|
+
await rs.close();
|
|
28
|
+
console.log('\n所有验证完成!');
|
|
29
|
+
process.exit(0);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('验证过程中出现错误:', error);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function testBasicMethods(rs) {
|
|
37
|
+
try {
|
|
38
|
+
// 测试文档中所有标记为✅的核心方法
|
|
39
|
+
const methods = [
|
|
40
|
+
{ name: 'set', result: await rs.set('temp_key', 'test_value') },
|
|
41
|
+
{ name: 'get', result: await rs.get('temp_key') },
|
|
42
|
+
{ name: 'has', result: await rs.has('temp_key') },
|
|
43
|
+
{ name: 'exists', result: await rs.exists('temp_key') },
|
|
44
|
+
{ name: 'ttl', result: await rs.ttl('temp_key') },
|
|
45
|
+
{ name: 'persist', result: await rs.persist('temp_key') },
|
|
46
|
+
{ name: 'add', result: await rs.add('new_temp_key', 'new_value') },
|
|
47
|
+
{ name: 'addInt', result: await rs.addInt('counter', 10) },
|
|
48
|
+
{ name: 'addStr', result: await rs.addStr('string_key', 'text') },
|
|
49
|
+
{ name: 'keys', result: await rs.keys('*') },
|
|
50
|
+
{ name: 'clear', result: await rs.clear('temp_key') },
|
|
51
|
+
{ name: 'del', result: await rs.del('new_temp_key') },
|
|
52
|
+
{ name: 'incr', result: await rs.incr('counter') },
|
|
53
|
+
{ name: 'decr', result: await rs.decr('counter') },
|
|
54
|
+
{ name: 'mget', result: await rs.mget(['counter', 'string_key']) },
|
|
55
|
+
{ name: 'mset', result: await rs.mset({batch1: 'value1', batch2: 'value2'}) },
|
|
56
|
+
{ name: 'expire', result: await rs.expire('counter', 60) },
|
|
57
|
+
// { name: 'type', result: await rs.type('counter') },
|
|
58
|
+
// { name: 'rename', result: await rs.rename('string_key', 'renamed_string') }
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
console.log('所有核心方法测试结果:');
|
|
62
|
+
methods.forEach(method => {
|
|
63
|
+
console.log(`- ${method.name}: ${typeof method.result !== 'undefined' ? '✅ 可用' : '❌ 不可用'}`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('核心方法测试失败:', error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function testRemovedMethods(rs) {
|
|
72
|
+
try {
|
|
73
|
+
// 测试文档中标记为❌的方法
|
|
74
|
+
const removedMethods = ['hexists', 'hkeys', 'hvals'];
|
|
75
|
+
|
|
76
|
+
console.log('移除方法测试结果:');
|
|
77
|
+
for (const method of removedMethods) {
|
|
78
|
+
try {
|
|
79
|
+
// 尝试调用移除的方法
|
|
80
|
+
if (typeof rs[method] === 'function') {
|
|
81
|
+
// 方法存在,尝试调用它
|
|
82
|
+
const result = await rs[method]('hash_key', 'field1');
|
|
83
|
+
console.log(`- ${method}: ⚠️ 方法存在,但根据兼容性表格应被移除`);
|
|
84
|
+
} else {
|
|
85
|
+
console.log(`- ${method}: ✅ 正确移除,方法不存在`);
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.log(`- ${method}: ✅ 调用失败,符合移除预期:`, err.message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('移除方法测试失败:', error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function testListMethods(rs) {
|
|
97
|
+
try {
|
|
98
|
+
// 测试列表操作方法
|
|
99
|
+
const listKey = 'list_test_key';
|
|
100
|
+
|
|
101
|
+
console.log('列表操作方法测试结果:');
|
|
102
|
+
|
|
103
|
+
// 测试list_set
|
|
104
|
+
const listSetResult = await rs.list_set(listKey, ["item1", "item2", "item3"]);
|
|
105
|
+
console.log(`- list_set: ${listSetResult ? '✅ 成功' : '❌ 失败'}`);
|
|
106
|
+
|
|
107
|
+
// 测试list_get
|
|
108
|
+
const listGetResult = await rs.list_get(listKey);
|
|
109
|
+
console.log(`- list_get: ${Array.isArray(listGetResult) ? '✅ 成功' : '❌ 失败'}`, listGetResult);
|
|
110
|
+
|
|
111
|
+
// 测试list_add
|
|
112
|
+
const listAddResult = await rs.list_add(listKey, "item4");
|
|
113
|
+
console.log(`- list_add: ${listAddResult ? '✅ 成功' : '❌ 失败'}`);
|
|
114
|
+
|
|
115
|
+
// 测试list_has
|
|
116
|
+
const listHasResult = await rs.list_has(listKey, "item2");
|
|
117
|
+
console.log(`- list_has: ${typeof listHasResult === 'boolean' ? '✅ 成功' : '❌ 失败'}`, listHasResult);
|
|
118
|
+
|
|
119
|
+
// 测试list_clear
|
|
120
|
+
const listClearResult = await rs.list_clear(listKey);
|
|
121
|
+
console.log(`- list_clear: ${listClearResult ? '✅ 成功' : '❌ 失败'}`);
|
|
122
|
+
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('列表操作方法测试失败:', error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
verifyCompatibility();
|
|
129
|
+
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
console.error('验证超时');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}, 15000); // 延长超时时间
|