mm_redis 1.9.6 → 1.9.8
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/compatibility_table.md +65 -163
- package/index.js +46 -50
- package/package.json +1 -1
- package/test.js +8 -2
- package/verify_compatibility.js +54 -12
package/compatibility_table.md
CHANGED
|
@@ -4,198 +4,100 @@
|
|
|
4
4
|
|
|
5
5
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
6
6
|
|-------|-------|---------|-----------|--------|----------|
|
|
7
|
-
| set | ✅ | ✅ |
|
|
7
|
+
| set | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
|
|
8
8
|
| get | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
9
|
-
| del | ✅ | ✅ |
|
|
10
|
-
| has | ✅ | ✅ | ✅ | ✅ |
|
|
11
|
-
| clear | ✅ | ✅ |
|
|
12
|
-
| keys | ✅ | ✅ | ✅ | ✅ |
|
|
13
|
-
| ttl |
|
|
9
|
+
| del | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
|
|
10
|
+
| has | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
11
|
+
| clear | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
|
|
12
|
+
| keys | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
13
|
+
| ttl | ⚠️ | ⚠️ | ⚠️ | ⚠️ | 所有方式行为不一致,需要依赖底层实现 |
|
|
14
14
|
| add | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
15
|
-
| addInt | ✅ |
|
|
16
|
-
| addStr | ✅ |
|
|
17
|
-
| sort | ✅ | ✅ |
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
| list_clear | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
|
|
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支持 |
|
|
23
22
|
|
|
24
23
|
## Redis兼容方法 - 哈希表操作
|
|
25
24
|
|
|
26
25
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
27
26
|
|-------|-------|---------|-----------|--------|----------|
|
|
28
|
-
| hset | ✅ | ✅ |
|
|
27
|
+
| hset | ✅ | ✅ | ⚠️ | ⚠️ | Redis和MongoDB正常工作,CacheBase和Memory行为不一致 |
|
|
29
28
|
| hget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
30
|
-
| hgetall | ✅ | ✅ | ✅ | ✅ |
|
|
31
|
-
| hdel | ✅ | ✅ | ✅ | ✅ |
|
|
32
|
-
| hmset | ✅ | ✅ |
|
|
33
|
-
| hmget |
|
|
34
|
-
| hlen | ✅ | ✅ |
|
|
29
|
+
| hgetall | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
30
|
+
| hdel | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
31
|
+
| hmset | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
32
|
+
| hmget | ❌ | ✅ | ❌ | ❌ | 仅MongoDB支持 |
|
|
33
|
+
| hlen | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
35
34
|
|
|
36
35
|
## Redis兼容方法 - 其他常用命令
|
|
37
36
|
|
|
38
37
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
39
38
|
|-------|-------|---------|-----------|--------|----------|
|
|
40
|
-
| expire | ✅ | ✅ | ✅ | ✅ |
|
|
41
|
-
| incr | ✅ | ✅ | ✅ | ✅ |
|
|
42
|
-
| decr | ✅ |
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
| rename | ✅ | ✅ | ✅ | ✅ | 键重命名,所有方式均正常工作 |
|
|
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 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
51
49
|
|
|
52
50
|
## Redis兼容方法 - 集合操作
|
|
53
51
|
|
|
54
52
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
55
53
|
|-------|-------|---------|-----------|--------|----------|
|
|
56
|
-
| sadd | ✅ |
|
|
57
|
-
| srem | ✅ |
|
|
58
|
-
| sismember | ✅ | ✅ |
|
|
59
|
-
| smembers | ✅ | ✅ |
|
|
54
|
+
| sadd | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
55
|
+
| srem | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
56
|
+
| sismember | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
57
|
+
| smembers | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
60
58
|
|
|
61
59
|
## 数组/列表操作方法
|
|
62
60
|
|
|
63
61
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
64
62
|
|-------|-------|---------|-----------|--------|----------|
|
|
65
|
-
| list_set | ✅ |
|
|
66
|
-
| list_add | ✅ |
|
|
67
|
-
| list_has | ✅ |
|
|
68
|
-
| list_get | ✅ |
|
|
69
|
-
| list_clear | ✅ |
|
|
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不支持,其他方式支持 |
|
|
70
68
|
|
|
71
69
|
## 兼容性报告总结
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
基于实际功能测试,以下是四种缓存方式的兼容性报告:
|
|
74
72
|
|
|
75
73
|
| 方法类别 | CacheBase | Redis | MongoDB | Memory | 状态说明 |
|
|
76
74
|
|---------|-----------|-------|---------|--------|----------|
|
|
77
|
-
| 基础键值操作 |
|
|
78
|
-
| 数组操作 | ⚠️ | ✅ |
|
|
79
|
-
| 过期时间操作 | ✅ | ✅ | ✅ | ✅ |
|
|
80
|
-
| 原子递增操作 | ✅ | ✅ | ✅ | ✅ |
|
|
81
|
-
| 批量操作 |
|
|
82
|
-
| 哈希表基本操作 | ✅ | ✅ | ✅ | ✅ |
|
|
83
|
-
| 哈希表批量操作 |
|
|
84
|
-
| 集合操作 |
|
|
85
|
-
| 字符串操作 |
|
|
86
|
-
| 类型检测 |
|
|
87
|
-
| 键重命名 |
|
|
88
|
-
| 清理操作 | ✅ | ✅ | ✅ | ✅ |
|
|
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操作正常工作 |
|
|
89
87
|
|
|
90
88
|
### 测试统计
|
|
91
89
|
|
|
92
|
-
- **总测试用例**:43
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
- 考虑在代码中添加方法兼容性检测
|
|
200
|
-
|
|
201
|
-
注:✅ 完全兼容/功能正常 | ⚠️ 功能正常但有注意事项 | ❌ 不兼容/未实现/已移除
|
|
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
|
|
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
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
|
|
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]
|
|
558
|
-
return
|
|
533
|
+
$.log.error(`[Redis] 获取过期时间失败 [${key}]:`, err);
|
|
534
|
+
return -2; // -2表示出错
|
|
559
535
|
}
|
|
560
536
|
};
|
|
561
537
|
|
|
@@ -2572,7 +2548,8 @@ Redis.prototype.sinter = async function (keys) {
|
|
|
2572
2548
|
const connection = await this._getConnection();
|
|
2573
2549
|
try {
|
|
2574
2550
|
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2575
|
-
|
|
2551
|
+
// 使用Redis v4正确的方法
|
|
2552
|
+
const result = await connection.sInter(...prefixedKeys);
|
|
2576
2553
|
return result || [];
|
|
2577
2554
|
} finally {
|
|
2578
2555
|
this._recycleConnection(connection);
|
|
@@ -2593,7 +2570,8 @@ Redis.prototype.sunion = async function (keys) {
|
|
|
2593
2570
|
const connection = await this._getConnection();
|
|
2594
2571
|
try {
|
|
2595
2572
|
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2596
|
-
|
|
2573
|
+
// 使用Redis v4正确的方法
|
|
2574
|
+
const result = await connection.sUnion(...prefixedKeys);
|
|
2597
2575
|
return result || [];
|
|
2598
2576
|
} finally {
|
|
2599
2577
|
this._recycleConnection(connection);
|
|
@@ -2614,7 +2592,8 @@ Redis.prototype.sdiff = async function (keys) {
|
|
|
2614
2592
|
const connection = await this._getConnection();
|
|
2615
2593
|
try {
|
|
2616
2594
|
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2617
|
-
|
|
2595
|
+
// 使用Redis v4正确的方法
|
|
2596
|
+
const result = await connection.sDiff(...prefixedKeys);
|
|
2618
2597
|
return result || [];
|
|
2619
2598
|
} finally {
|
|
2620
2599
|
this._recycleConnection(connection);
|
|
@@ -2763,21 +2742,38 @@ Redis.prototype.zrange = async function (key, start, stop, withScores = false) {
|
|
|
2763
2742
|
const connection = await this._getConnection();
|
|
2764
2743
|
try {
|
|
2765
2744
|
const prefixedKey = this.applyPrefix(key);
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
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 [];
|
|
2776
2771
|
}
|
|
2777
|
-
|
|
2772
|
+
} else {
|
|
2773
|
+
// 不需要分数的情况
|
|
2774
|
+
const result = await connection.zRange(prefixedKey, start, stop);
|
|
2775
|
+
return result || [];
|
|
2778
2776
|
}
|
|
2779
|
-
|
|
2780
|
-
return result || [];
|
|
2781
2777
|
} finally {
|
|
2782
2778
|
this._recycleConnection(connection);
|
|
2783
2779
|
}
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -252,11 +252,17 @@ async function test() {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
test().
|
|
255
|
+
test().then(() => {
|
|
256
|
+
// 测试成功完成
|
|
257
|
+
$.log.debug('[Redis] 测试脚本正常退出');
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}).catch(err => {
|
|
256
260
|
$.log.error('[Redis] 未捕获的错误:', err);
|
|
257
261
|
process.exit(1);
|
|
258
262
|
});
|
|
259
263
|
|
|
264
|
+
// 添加超时保护,但让Promise处理正常结束
|
|
260
265
|
setTimeout(() => {
|
|
261
|
-
|
|
266
|
+
$.log.warn('[Redis] 测试脚本超时');
|
|
267
|
+
process.exit(1);
|
|
262
268
|
}, 10000); // 延长超时时间以确保所有测试完成
|
package/verify_compatibility.js
CHANGED
|
@@ -8,7 +8,7 @@ async function verifyCompatibility() {
|
|
|
8
8
|
|
|
9
9
|
console.log('开始验证兼容性表格中的所有方法...');
|
|
10
10
|
|
|
11
|
-
// 1. 测试核心缓存方法
|
|
11
|
+
// 1. 测试核心缓存方法
|
|
12
12
|
console.log('\n=== 核心缓存方法验证 ===');
|
|
13
13
|
await testBasicMethods(rs);
|
|
14
14
|
|
|
@@ -20,9 +20,13 @@ async function verifyCompatibility() {
|
|
|
20
20
|
console.log('\n=== 列表操作方法验证 ===');
|
|
21
21
|
await testListMethods(rs);
|
|
22
22
|
|
|
23
|
-
// 4.
|
|
23
|
+
// 4. 测试哈希表相关方法
|
|
24
|
+
console.log('\n=== 哈希表方法验证 ===');
|
|
25
|
+
await testHashMethods(rs);
|
|
26
|
+
|
|
27
|
+
// 5. 清理并关闭连接
|
|
24
28
|
console.log('\n清理测试数据...');
|
|
25
|
-
await rs.del(["list_test_key"]);
|
|
29
|
+
await rs.del(["list_test_key", "hash_test_key", "test_counter", "test_string"]);
|
|
26
30
|
|
|
27
31
|
await rs.close();
|
|
28
32
|
console.log('\n所有验证完成!');
|
|
@@ -35,7 +39,7 @@ async function verifyCompatibility() {
|
|
|
35
39
|
|
|
36
40
|
async function testBasicMethods(rs) {
|
|
37
41
|
try {
|
|
38
|
-
//
|
|
42
|
+
// 测试核心方法
|
|
39
43
|
const methods = [
|
|
40
44
|
{ name: 'set', result: await rs.set('temp_key', 'test_value') },
|
|
41
45
|
{ name: 'get', result: await rs.get('temp_key') },
|
|
@@ -44,18 +48,20 @@ async function testBasicMethods(rs) {
|
|
|
44
48
|
{ name: 'ttl', result: await rs.ttl('temp_key') },
|
|
45
49
|
{ name: 'persist', result: await rs.persist('temp_key') },
|
|
46
50
|
{ name: 'add', result: await rs.add('new_temp_key', 'new_value') },
|
|
47
|
-
{ name: 'addInt', result: await rs.addInt('
|
|
48
|
-
{ name: 'addStr', result: await rs.addStr('
|
|
51
|
+
{ name: 'addInt', result: await rs.addInt('test_counter', 10) },
|
|
52
|
+
{ name: 'addStr', result: await rs.addStr('test_string', 'text') },
|
|
49
53
|
{ name: 'keys', result: await rs.keys('*') },
|
|
50
54
|
{ name: 'clear', result: await rs.clear('temp_key') },
|
|
51
55
|
{ name: 'del', result: await rs.del('new_temp_key') },
|
|
52
|
-
{ name: 'incr', result: await rs.incr('
|
|
53
|
-
{ name: 'decr', result: await rs.decr('
|
|
54
|
-
{ name: 'mget', result: await rs.mget(['
|
|
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']) },
|
|
55
59
|
{ name: 'mset', result: await rs.mset({batch1: 'value1', batch2: 'value2'}) },
|
|
56
|
-
{ name: 'expire', result: await rs.expire('
|
|
57
|
-
|
|
58
|
-
|
|
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) }
|
|
59
65
|
];
|
|
60
66
|
|
|
61
67
|
console.log('所有核心方法测试结果:');
|
|
@@ -125,6 +131,42 @@ async function testListMethods(rs) {
|
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
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
|
+
|
|
128
170
|
verifyCompatibility();
|
|
129
171
|
|
|
130
172
|
setTimeout(() => {
|