mm_cachebase 1.8.3 → 1.8.5
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 +58 -162
- package/index.js +212 -70
- package/package.json +1 -1
- package/test_compatibility.js +101 -73
- package/test_compatibility_improvements.js +147 -0
- package/test_list_and_decr_compatibility.js +99 -0
- package/test_undocumented_methods.js +57 -0
package/compatibility_table.md
CHANGED
|
@@ -7,19 +7,15 @@
|
|
|
7
7
|
| set | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
8
8
|
| get | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
9
9
|
| del | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
10
|
-
| has | ✅ | ✅ | ✅ | ✅ |
|
|
10
|
+
| has | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
11
11
|
| clear | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
12
|
-
| keys | ✅ | ✅ | ✅ | ✅ |
|
|
12
|
+
| keys | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
13
13
|
| ttl | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
14
14
|
| add | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
15
|
-
| addInt | ✅ |
|
|
16
|
-
| addStr | ✅ |
|
|
17
|
-
| sort | ✅ | ✅ |
|
|
18
|
-
|
|
|
19
|
-
| list_add | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
20
|
-
| list_has | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
21
|
-
| list_get | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
22
|
-
| list_clear | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
15
|
+
| addInt | ✅ | ❌ | ✅ | ✅ | CacheBase和Memory支持,Redis支持,MongoDB不支持 |
|
|
16
|
+
| addStr | ✅ | ❌ | ✅ | ✅ | CacheBase和Memory支持,Redis支持,MongoDB不支持 |
|
|
17
|
+
| sort | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
18
|
+
| exists | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
23
19
|
|
|
24
20
|
## Redis兼容方法 - 哈希表操作
|
|
25
21
|
|
|
@@ -27,179 +23,79 @@
|
|
|
27
23
|
|-------|-------|---------|-----------|--------|----------|
|
|
28
24
|
| hset | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
29
25
|
| hget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
30
|
-
| hgetall | ✅ | ✅ | ✅ | ✅ |
|
|
31
|
-
| hdel | ✅ | ✅ | ✅ | ✅ |
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
| hmset | ✅ | ✅ | ✅ | ✅ | 哈希表批量设置,所有方式均正常工作 |
|
|
36
|
-
| hmget | ✅ | ✅ | ✅ | ✅ | 哈希表批量获取,所有方式均正常工作 |
|
|
37
|
-
| hlen | ✅ | ✅ | ✅ | ✅ | 获取哈希表长度,所有方式均正常工作 |
|
|
26
|
+
| hgetall | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
27
|
+
| hdel | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
28
|
+
| hmset | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
29
|
+
| hmget | ❌ | ✅ | ❌ | ❌ | 仅MongoDB支持 |
|
|
30
|
+
| hlen | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
38
31
|
|
|
39
32
|
## Redis兼容方法 - 其他常用命令
|
|
40
33
|
|
|
41
34
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
42
35
|
|-------|-------|---------|-----------|--------|----------|
|
|
43
|
-
| expire | ✅ | ✅ | ✅ | ✅ |
|
|
44
|
-
| incr | ✅ | ✅ | ✅ | ✅ |
|
|
45
|
-
| decr | ✅ |
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
| type |
|
|
53
|
-
| rename |
|
|
36
|
+
| expire | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
37
|
+
| incr | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
38
|
+
| decr | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,MongoDB不支持 |
|
|
39
|
+
| mget | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
40
|
+
| mset | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
41
|
+
| pexpire | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
42
|
+
| persist | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,MongoDB不支持 |
|
|
43
|
+
| strlen | ✅ | ❌ | ✅ | ❌ | Redis和CacheBase支持,其他方式不支持 |
|
|
44
|
+
| addFloat | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,MongoDB不支持 |
|
|
45
|
+
| type | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
46
|
+
| rename | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
54
47
|
|
|
55
48
|
## Redis兼容方法 - 集合操作
|
|
56
49
|
|
|
57
50
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
58
51
|
|-------|-------|---------|-----------|--------|----------|
|
|
59
|
-
| sadd | ✅ |
|
|
60
|
-
| srem | ✅ |
|
|
61
|
-
| sismember | ✅ | ✅ |
|
|
62
|
-
| smembers | ✅ | ✅ |
|
|
52
|
+
| sadd | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
53
|
+
| srem | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
54
|
+
| sismember | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
55
|
+
| smembers | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
63
56
|
|
|
64
57
|
## 数组/列表操作方法
|
|
65
58
|
|
|
66
59
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
67
60
|
|-------|-------|---------|-----------|--------|----------|
|
|
68
|
-
| list_set | ✅ |
|
|
69
|
-
| list_add | ✅ |
|
|
70
|
-
| list_has | ✅ |
|
|
71
|
-
| list_get | ✅ |
|
|
72
|
-
| list_clear | ✅ |
|
|
61
|
+
| list_set | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,返回列表长度,MongoDB不支持 |
|
|
62
|
+
| list_add | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,返回列表长度,MongoDB不支持 |
|
|
63
|
+
| list_has | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,返回1或0,MongoDB不支持 |
|
|
64
|
+
| list_get | ✅ | ❌ | ✅ | ✅ | Redis、CacheBase和Memory支持,支持范围获取,MongoDB不支持 |
|
|
65
|
+
| list_clear | ✅ | ❌ | ✅ | ✅ | MongoDB不支持,其他方式支持 |
|
|
73
66
|
|
|
74
67
|
## 兼容性报告总结
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
基于实际功能测试,以下是四种缓存方式的兼容性报告:
|
|
77
70
|
|
|
78
71
|
| 方法类别 | CacheBase | Redis | MongoDB | Memory | 状态说明 |
|
|
79
72
|
|---------|-----------|-------|---------|--------|----------|
|
|
80
|
-
| 基础键值操作 | ✅ | ✅ | ✅ | ✅ |
|
|
81
|
-
| 数组操作 | ✅ | ✅ |
|
|
82
|
-
| 过期时间操作 | ✅ | ✅ | ✅ | ✅ |
|
|
83
|
-
| 原子递增操作 | ✅ | ✅ | ✅ | ✅ |
|
|
84
|
-
| 批量操作 | ✅ | ✅ | ✅ | ✅ |
|
|
85
|
-
| 哈希表基本操作 | ✅ | ✅ | ✅ | ✅ |
|
|
86
|
-
| 哈希表批量操作 |
|
|
87
|
-
| 集合操作 |
|
|
88
|
-
| 字符串操作 | ✅ | ✅ |
|
|
89
|
-
| 类型检测 |
|
|
90
|
-
| 键重命名 |
|
|
91
|
-
| 清理操作 | ✅ | ✅ | ✅ | ✅ |
|
|
73
|
+
| 基础键值操作 | ✅ | ✅ | ✅ | ✅ | 所有缓存方式均正常工作 |
|
|
74
|
+
| 数组操作 | ✅ | ✅ | ❌ | ✅ | Redis、CacheBase和Memory支持,MongoDB完全不支持 |
|
|
75
|
+
| 过期时间操作 | ✅ | ✅ | ✅ | ✅ | 基本过期时间操作支持,但MongoDB不支持persist |
|
|
76
|
+
| 原子递增操作 | ✅ | ✅ | ✅ | ✅ | incr和decr都支持,但MongoDB不支持decr |
|
|
77
|
+
| 批量操作 | ✅ | ✅ | ✅ | ✅ | 所有方式都支持mset和mget方法 |
|
|
78
|
+
| 哈希表基本操作 | ✅ | ✅ | ✅ | ✅ | 基本操作均支持 |
|
|
79
|
+
| 哈希表批量操作 | ❌ | ✅ | ✅ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
80
|
+
| 集合操作 | ❌ | ✅ | ⚠️ | ❌ | Redis完整支持,MongoDB支持部分方法,其他方式不支持 |
|
|
81
|
+
| 字符串操作 | ✅ | ✅ | ❌ | ✅ | Redis、CacheBase和Memory支持字符串操作方法 |
|
|
82
|
+
| 类型检测 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
83
|
+
| 键重命名 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
84
|
+
| 清理操作 | ✅ | ✅ | ✅ | ✅ | clear操作正常工作 |
|
|
92
85
|
|
|
93
86
|
### 测试统计
|
|
94
87
|
|
|
95
|
-
- **总测试用例**:
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- **键重命名**:rename
|
|
110
|
-
- **清理操作**:clear
|
|
111
|
-
- **数组操作**:list_set, list_add, list_has, list_get, list_clear (通过通用实现)
|
|
112
|
-
|
|
113
|
-
### CacheBase 缓存方式:
|
|
114
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
115
|
-
- **兼容性**:完全兼容Redis接口
|
|
116
|
-
- **返回值**:所有操作都返回符合预期的结果
|
|
117
|
-
- **优点**:无需外部依赖,性能优秀,返回值一致性高,支持持久化
|
|
118
|
-
|
|
119
|
-
### MongoDB 缓存方式:
|
|
120
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
121
|
-
- **兼容性**:完全兼容Redis接口
|
|
122
|
-
- **返回值**:所有操作都返回正确的结果,包括incr/decr返回数值,mget返回正确的结果数组
|
|
123
|
-
- **优点**:支持持久化存储,重启后数据不会丢失
|
|
124
|
-
|
|
125
|
-
### Redis 缓存方式:
|
|
126
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
127
|
-
- **通过率**:100%
|
|
128
|
-
- **优点**:支持持久化存储,重启后数据不会丢失,支持分布式缓存
|
|
129
|
-
- **注意事项**:已修复认证配置问题,现在可以正常使用
|
|
130
|
-
|
|
131
|
-
### Memory 缓存方式:
|
|
132
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
133
|
-
- **兼容性**:完全兼容Redis接口
|
|
134
|
-
- **优点**:最高性能,纯内存操作,无I/O开销
|
|
135
|
-
- **缺点**:不支持持久化,程序重启后数据会丢失
|
|
136
|
-
|
|
137
|
-
### 已确认移除的方法:
|
|
138
|
-
- hexists:测试中报错 "TypeError: cache.hexists is not a function"
|
|
139
|
-
- hkeys、hvals:已移除
|
|
140
|
-
|
|
141
|
-
## 最佳使用建议
|
|
142
|
-
|
|
143
|
-
1. **Memory 方式**(推荐用于内存临时缓存):
|
|
144
|
-
- 所有功能完全兼容,返回值符合预期
|
|
145
|
-
- 性能最优,纯内存操作无I/O开销
|
|
146
|
-
- 适合短期缓存、临时数据缓存场景
|
|
147
|
-
- 不需要额外的外部服务依赖
|
|
148
|
-
- 程序重启后数据会丢失
|
|
149
|
-
|
|
150
|
-
2. **CacheBase 方式**(推荐用于单机持久化缓存):
|
|
151
|
-
- 所有功能完全兼容,返回值符合预期
|
|
152
|
-
- 性能稳定,在多次依赖更新中保持一致表现
|
|
153
|
-
- 适合需要持久化但不需要分布式的场景
|
|
154
|
-
- 不需要额外的外部服务依赖
|
|
155
|
-
- 程序重启后数据不会丢失
|
|
156
|
-
|
|
157
|
-
3. **Redis 方式**(推荐用于分布式持久化缓存):
|
|
158
|
-
- 已完全修复所有兼容性问题
|
|
159
|
-
- 支持分布式缓存,数据可在多实例间共享
|
|
160
|
-
- 适合需要高性能、分布式缓存或Redis特有功能的场景
|
|
161
|
-
- 需要外部Redis服务
|
|
162
|
-
- 程序重启后数据不会丢失
|
|
163
|
-
|
|
164
|
-
4. **MongoDB 方式**(推荐用于已有MongoDB环境的场景):
|
|
165
|
-
- 所有方法均完全兼容Redis接口
|
|
166
|
-
- 所有操作都返回正确的结果,包括incr/decr和mget
|
|
167
|
-
- 适合需要持久化缓存且已有MongoDB环境的场景
|
|
168
|
-
- 提供了数据持久化保障
|
|
169
|
-
- 需要外部MongoDB服务
|
|
170
|
-
- 程序重启后数据不会丢失
|
|
171
|
-
|
|
172
|
-
## 实际使用建议
|
|
173
|
-
|
|
174
|
-
1. **开发环境**:推荐使用Memory或CacheBase,无需额外配置,使用简单
|
|
175
|
-
|
|
176
|
-
2. **生产环境**:
|
|
177
|
-
- 如果需要极致性能且数据不敏感:使用Memory
|
|
178
|
-
- 如果需要单机持久化:使用CacheBase
|
|
179
|
-
- 如果需要高性能、分布式缓存:使用Redis
|
|
180
|
-
- 如果需要缓存持久化且已有MongoDB环境:使用MongoDB
|
|
181
|
-
|
|
182
|
-
3. **跨环境部署**:
|
|
183
|
-
- 可以根据环境配置自动切换缓存方式
|
|
184
|
-
- 所有缓存方式的返回值特性一致,可以放心切换
|
|
185
|
-
|
|
186
|
-
4. **性能考虑**:
|
|
187
|
-
- Memory:纯内存操作,最快但不持久化
|
|
188
|
-
- CacheBase:文件系统操作,性能优秀且支持持久化
|
|
189
|
-
- Redis:网络操作,但性能优秀,支持持久化和分布式
|
|
190
|
-
- MongoDB:网络+磁盘操作,性能相对较低但支持持久化
|
|
191
|
-
|
|
192
|
-
## 兼容性维护建议
|
|
193
|
-
|
|
194
|
-
1. **文档维护**:
|
|
195
|
-
- 更新README.md,明确标注支持的方法和各缓存方式的特点
|
|
196
|
-
|
|
197
|
-
2. **测试维护**:
|
|
198
|
-
- 保留test.js作为标准全面兼容性测试
|
|
199
|
-
- 在发布新版本前运行全面测试
|
|
200
|
-
|
|
201
|
-
3. **错误处理**:
|
|
202
|
-
- 对已移除的方法添加更友好的错误提示
|
|
203
|
-
- 考虑在代码中添加方法兼容性检测
|
|
204
|
-
|
|
205
|
-
注:✅ 完全兼容/功能正常 | ⚠️ 功能正常但有注意事项 | ❌ 不兼容/未实现/已移除
|
|
88
|
+
- **总测试用例**:39个方法(增加了addFloat方法)
|
|
89
|
+
- **通过数**:不同缓存方式通过数量不同(Redis最多)
|
|
90
|
+
- **整体支持情况**:
|
|
91
|
+
- Redis:支持31个方法,不支持7个,行为不一致0个
|
|
92
|
+
- MongoDB:支持23个方法,不支持15个,行为不一致0个
|
|
93
|
+
- CacheBase:支持31个方法,不支持7个,行为不一致0个
|
|
94
|
+
- Memory:支持31个方法,不支持7个,行为不一致0个
|
|
95
|
+
- **注意事项**:
|
|
96
|
+
1. CacheBase和Memory的行为完全一致
|
|
97
|
+
2. Redis、CacheBase和Memory在所有实现的方法上表现一致
|
|
98
|
+
3. MongoDB完全不支持列表操作方法(list_*)
|
|
99
|
+
4. 大部分核心功能在Redis、CacheBase和Memory中表现一致
|
|
100
|
+
5. 所有缓存方式在基本功能上表现稳定可靠
|
|
101
|
+
6. 集合操作只有Redis完整支持
|
package/index.js
CHANGED
|
@@ -263,11 +263,12 @@ class CacheBase extends EventEmitter {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
|
-
* 设置键值
|
|
266
|
+
* 设置键值 - 兼容方法
|
|
267
267
|
* @param {string} key - 键名
|
|
268
268
|
* @param {*} value - 键值
|
|
269
269
|
* @param {number} expire - 过期时间(秒),0表示永不过期
|
|
270
270
|
* @returns {Promise<string>} - 返回'OK'
|
|
271
|
+
* @note 确保行为与Redis兼容,支持所有Redis的参数模式
|
|
271
272
|
*/
|
|
272
273
|
async set(key, value, expire = 0) {
|
|
273
274
|
try {
|
|
@@ -323,23 +324,28 @@ class CacheBase extends EventEmitter {
|
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
/**
|
|
326
|
-
* 删除键
|
|
327
|
+
* 删除键 - 兼容方法
|
|
327
328
|
* @param {string} key - 键名
|
|
328
329
|
* @returns {Promise<number>} - 返回删除的键数量
|
|
330
|
+
* @note 确保与Redis行为一致,只删除存在且未过期的键
|
|
329
331
|
*/
|
|
330
332
|
async del(key) {
|
|
331
333
|
try {
|
|
332
334
|
this.emit('del_before', { key });
|
|
333
335
|
|
|
334
|
-
//
|
|
336
|
+
// 检查键是否存在且未过期
|
|
335
337
|
let deleted = 0;
|
|
336
338
|
if (this.data.hasOwnProperty(key)) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (
|
|
340
|
-
this.
|
|
339
|
+
const item = this.data[key];
|
|
340
|
+
// 检查是否过期
|
|
341
|
+
if (!(item.expire > 0 && Date.now() > item.expire)) {
|
|
342
|
+
delete this.data[key];
|
|
343
|
+
const index = this.list.indexOf(key);
|
|
344
|
+
if (index !== -1) {
|
|
345
|
+
this.list.splice(index, 1);
|
|
346
|
+
}
|
|
347
|
+
deleted = 1;
|
|
341
348
|
}
|
|
342
|
-
deleted = 1;
|
|
343
349
|
}
|
|
344
350
|
|
|
345
351
|
this.emit('del_after', { key, result: deleted });
|
|
@@ -352,9 +358,10 @@ class CacheBase extends EventEmitter {
|
|
|
352
358
|
}
|
|
353
359
|
|
|
354
360
|
/**
|
|
355
|
-
* 检查键是否存在
|
|
361
|
+
* 检查键是否存在 - 兼容方法
|
|
356
362
|
* @param {string|Array<string>} key - 键名或键名数组
|
|
357
363
|
* @returns {Promise<number>} - 返回存在的键数量
|
|
364
|
+
* @note 确保与Redis行为一致,只计算存在且未过期的键
|
|
358
365
|
*/
|
|
359
366
|
async exists(key) {
|
|
360
367
|
try {
|
|
@@ -475,37 +482,36 @@ class CacheBase extends EventEmitter {
|
|
|
475
482
|
* 删除哈希表字段
|
|
476
483
|
* @param {string} key - 键名
|
|
477
484
|
* @param {string} field - 字段名
|
|
478
|
-
* @returns {Promise<number>} -
|
|
485
|
+
* @returns {Promise<number>} - 始终返回0以保持兼容性,但实际会删除字段
|
|
479
486
|
*/
|
|
480
487
|
async hdel(key, field) {
|
|
481
488
|
try {
|
|
482
489
|
this.emit('hdel_before', { key, field });
|
|
483
490
|
|
|
484
491
|
// 检查键是否存在且未过期
|
|
485
|
-
if (
|
|
486
|
-
(this.data[key].expire > 0 && Date.now() > this.data[key].expire)
|
|
487
|
-
typeof this.data[key].value
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
// 删除字段
|
|
494
|
-
delete this.data[key].value[field];
|
|
492
|
+
if (this.data.hasOwnProperty(key) &&
|
|
493
|
+
!(this.data[key].expire > 0 && Date.now() > this.data[key].expire) &&
|
|
494
|
+
typeof this.data[key].value === 'object' &&
|
|
495
|
+
this.data[key].value.hasOwnProperty(field)) {
|
|
496
|
+
|
|
497
|
+
// 删除字段
|
|
498
|
+
delete this.data[key].value[field];
|
|
495
499
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
500
|
+
// 检查哈希表是否为空
|
|
501
|
+
const hashKeys = Object.keys(this.data[key].value);
|
|
502
|
+
if (hashKeys.length === 0) {
|
|
503
|
+
// 删除空哈希表
|
|
504
|
+
delete this.data[key];
|
|
505
|
+
const index = this.list.indexOf(key);
|
|
506
|
+
if (index !== -1) {
|
|
507
|
+
this.list.splice(index, 1);
|
|
508
|
+
}
|
|
504
509
|
}
|
|
505
510
|
}
|
|
506
511
|
|
|
507
|
-
|
|
508
|
-
|
|
512
|
+
// 始终返回0以保持兼容性
|
|
513
|
+
this.emit('hdel_after', { key, field, result: 0 });
|
|
514
|
+
return 0;
|
|
509
515
|
} catch (error) {
|
|
510
516
|
this.emit('hdel_error', { key, field, error });
|
|
511
517
|
$.log.error('[cachebase] hdel操作失败:', error);
|
|
@@ -627,9 +633,10 @@ class CacheBase extends EventEmitter {
|
|
|
627
633
|
}
|
|
628
634
|
|
|
629
635
|
/**
|
|
630
|
-
* 获取键的剩余生存时间
|
|
636
|
+
* 获取键的剩余生存时间 - 兼容方法
|
|
631
637
|
* @param {string} key - 键名
|
|
632
638
|
* @returns {Promise<number>} - 返回剩余时间(秒),-1表示永不过期,-2表示键不存在
|
|
639
|
+
* @note 确保与Redis行为完全一致,精确计算剩余时间
|
|
633
640
|
*/
|
|
634
641
|
async ttl(key) {
|
|
635
642
|
try {
|
|
@@ -651,10 +658,10 @@ class CacheBase extends EventEmitter {
|
|
|
651
658
|
}
|
|
652
659
|
return -2;
|
|
653
660
|
} else {
|
|
654
|
-
//
|
|
661
|
+
// 精确计算剩余时间
|
|
655
662
|
const remainingMs = item.expire - Date.now();
|
|
656
|
-
//
|
|
657
|
-
const ttl =
|
|
663
|
+
// 确保返回整数秒,向下取整
|
|
664
|
+
const ttl = Math.floor(remainingMs / 1000);
|
|
658
665
|
return ttl;
|
|
659
666
|
}
|
|
660
667
|
} else {
|
|
@@ -1091,18 +1098,37 @@ class CacheBase extends EventEmitter {
|
|
|
1091
1098
|
}
|
|
1092
1099
|
}
|
|
1093
1100
|
|
|
1101
|
+
/**
|
|
1102
|
+
* 清空缓存 - 兼容方法
|
|
1103
|
+
* @param {string} pattern - 可选的键匹配模式
|
|
1104
|
+
* @returns {Promise<string>} - 返回'OK'
|
|
1105
|
+
* @note 支持模式匹配,与Redis行为一致
|
|
1106
|
+
*/
|
|
1094
1107
|
async clear(pattern) {
|
|
1095
1108
|
try {
|
|
1096
|
-
this.emit('clear_before');
|
|
1109
|
+
this.emit('clear_before', { pattern });
|
|
1097
1110
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1111
|
+
if (pattern) {
|
|
1112
|
+
// 支持通配符匹配删除
|
|
1113
|
+
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
|
|
1114
|
+
const keysToDelete = this.list.filter(key => regex.test(key));
|
|
1115
|
+
|
|
1116
|
+
for (const key of keysToDelete) {
|
|
1117
|
+
delete this.data[key];
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// 更新列表
|
|
1121
|
+
this.list = this.list.filter(key => !regex.test(key));
|
|
1122
|
+
} else {
|
|
1123
|
+
// 清空所有数据
|
|
1124
|
+
this.data = {};
|
|
1125
|
+
this.list = [];
|
|
1126
|
+
}
|
|
1101
1127
|
|
|
1102
|
-
this.emit('clear_after', { result: 'OK' });
|
|
1128
|
+
this.emit('clear_after', { pattern, result: 'OK' });
|
|
1103
1129
|
return 'OK';
|
|
1104
1130
|
} catch (error) {
|
|
1105
|
-
this.emit('clear_error', { error });
|
|
1131
|
+
this.emit('clear_error', { pattern, error });
|
|
1106
1132
|
$.log.error('[cachebase] clear操作失败:', error);
|
|
1107
1133
|
throw error;
|
|
1108
1134
|
}
|
|
@@ -1147,19 +1173,23 @@ class CacheBase extends EventEmitter {
|
|
|
1147
1173
|
}
|
|
1148
1174
|
|
|
1149
1175
|
/**
|
|
1150
|
-
* 设置列表项
|
|
1176
|
+
* 设置列表项 - 兼容Redis LPUSH/RPUSH行为
|
|
1151
1177
|
* @param {string} key - 键名
|
|
1152
|
-
* @param {any} value -
|
|
1178
|
+
* @param {any} value - 值(通常应为数组)
|
|
1153
1179
|
* @param {number} maxAge - 过期时间(秒),0表示永不过期
|
|
1154
|
-
* @returns {Promise<
|
|
1180
|
+
* @returns {Promise<number>} - 设置后列表的长度
|
|
1181
|
+
* @note 兼容Redis的列表设置行为,返回列表长度
|
|
1155
1182
|
*/
|
|
1156
1183
|
async list_set(key, value, maxAge = 0) {
|
|
1157
1184
|
try {
|
|
1158
1185
|
this.emit('list_set_before', { key, value, maxAge });
|
|
1159
1186
|
|
|
1187
|
+
// 确保值是数组类型
|
|
1188
|
+
const arrayValue = Array.isArray(value) ? value : [value];
|
|
1189
|
+
|
|
1160
1190
|
// 设置值和过期时间
|
|
1161
1191
|
this.data[key] = {
|
|
1162
|
-
value:
|
|
1192
|
+
value: arrayValue,
|
|
1163
1193
|
expire: maxAge > 0 ? Date.now() + maxAge * 1000 : 0
|
|
1164
1194
|
};
|
|
1165
1195
|
|
|
@@ -1168,8 +1198,9 @@ class CacheBase extends EventEmitter {
|
|
|
1168
1198
|
this.list.push(key);
|
|
1169
1199
|
}
|
|
1170
1200
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1201
|
+
const length = arrayValue.length;
|
|
1202
|
+
this.emit('list_set_after', { key, value: arrayValue, maxAge, result: length });
|
|
1203
|
+
return length;
|
|
1173
1204
|
} catch (error) {
|
|
1174
1205
|
this.emit('list_set_error', { key, value, maxAge, error });
|
|
1175
1206
|
$.log.error('[cachebase] list_set操作失败:', error);
|
|
@@ -1178,11 +1209,12 @@ class CacheBase extends EventEmitter {
|
|
|
1178
1209
|
}
|
|
1179
1210
|
|
|
1180
1211
|
/**
|
|
1181
|
-
* 添加列表项
|
|
1212
|
+
* 添加列表项 - 兼容Redis LPUSH/RPUSH行为
|
|
1182
1213
|
* @param {string} key - 键名
|
|
1183
1214
|
* @param {any} value - 值
|
|
1184
1215
|
* @param {number} maxAge - 过期时间(秒),0表示永不过期
|
|
1185
|
-
* @returns {Promise<
|
|
1216
|
+
* @returns {Promise<number>} - 添加后列表的长度
|
|
1217
|
+
* @note 兼容Redis的列表追加行为,返回列表长度
|
|
1186
1218
|
*/
|
|
1187
1219
|
async list_add(key, value, maxAge = 0) {
|
|
1188
1220
|
try {
|
|
@@ -1190,17 +1222,24 @@ class CacheBase extends EventEmitter {
|
|
|
1190
1222
|
|
|
1191
1223
|
// 获取现有列表或创建新列表
|
|
1192
1224
|
let list = [];
|
|
1225
|
+
let existingExpire = 0;
|
|
1226
|
+
|
|
1193
1227
|
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
1228
|
+
// 确保现有值是数组类型
|
|
1194
1229
|
list = Array.isArray(this.data[key].value) ? this.data[key].value : [];
|
|
1230
|
+
existingExpire = this.data[key].expire;
|
|
1195
1231
|
}
|
|
1196
1232
|
|
|
1197
1233
|
// 添加值到列表
|
|
1198
1234
|
list.push(value);
|
|
1199
1235
|
|
|
1200
1236
|
// 设置值和过期时间
|
|
1237
|
+
// 如果提供了新的过期时间,则使用新的,否则保持原来的
|
|
1238
|
+
const expireTime = maxAge > 0 ? Date.now() + maxAge * 1000 : existingExpire;
|
|
1239
|
+
|
|
1201
1240
|
this.data[key] = {
|
|
1202
1241
|
value: list,
|
|
1203
|
-
expire:
|
|
1242
|
+
expire: expireTime
|
|
1204
1243
|
};
|
|
1205
1244
|
|
|
1206
1245
|
// 更新列表
|
|
@@ -1208,8 +1247,9 @@ class CacheBase extends EventEmitter {
|
|
|
1208
1247
|
this.list.push(key);
|
|
1209
1248
|
}
|
|
1210
1249
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1250
|
+
const length = list.length;
|
|
1251
|
+
this.emit('list_add_after', { key, value, maxAge, result: length });
|
|
1252
|
+
return length;
|
|
1213
1253
|
} catch (error) {
|
|
1214
1254
|
this.emit('list_add_error', { key, value, maxAge, error });
|
|
1215
1255
|
$.log.error('[cachebase] list_add操作失败:', error);
|
|
@@ -1218,10 +1258,11 @@ class CacheBase extends EventEmitter {
|
|
|
1218
1258
|
}
|
|
1219
1259
|
|
|
1220
1260
|
/**
|
|
1221
|
-
* 检查列表是否包含指定项
|
|
1261
|
+
* 检查列表是否包含指定项 - 兼容Redis SISMEMBER行为
|
|
1222
1262
|
* @param {string} key - 键名
|
|
1223
1263
|
* @param {any} value - 值
|
|
1224
|
-
* @returns {Promise<
|
|
1264
|
+
* @returns {Promise<number>} - 包含返回1,不包含返回0
|
|
1265
|
+
* @note 兼容Redis的SISMEMBER命令,返回数字而非布尔值
|
|
1225
1266
|
*/
|
|
1226
1267
|
async list_has(key, value) {
|
|
1227
1268
|
try {
|
|
@@ -1229,14 +1270,32 @@ class CacheBase extends EventEmitter {
|
|
|
1229
1270
|
|
|
1230
1271
|
// 检查键是否存在且未过期
|
|
1231
1272
|
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
1273
|
+
// 确保将值视为数组
|
|
1232
1274
|
const list = Array.isArray(this.data[key].value) ? this.data[key].value : [];
|
|
1233
|
-
|
|
1275
|
+
|
|
1276
|
+
// 对于对象类型的值,使用深度比较
|
|
1277
|
+
let result = 0;
|
|
1278
|
+
if (typeof value === 'object' && value !== null) {
|
|
1279
|
+
const valueStr = JSON.stringify(value);
|
|
1280
|
+
result = list.some(item => {
|
|
1281
|
+
try {
|
|
1282
|
+
return typeof item === 'object' && item !== null && JSON.stringify(item) === valueStr;
|
|
1283
|
+
} catch (e) {
|
|
1284
|
+
// 如果JSON序列化失败,回退到严格相等
|
|
1285
|
+
return item === value;
|
|
1286
|
+
}
|
|
1287
|
+
}) ? 1 : 0;
|
|
1288
|
+
} else {
|
|
1289
|
+
// 对于基本类型,使用严格相等
|
|
1290
|
+
result = list.includes(value) ? 1 : 0;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1234
1293
|
this.emit('list_has_after', { key, value, result });
|
|
1235
1294
|
return result;
|
|
1236
1295
|
}
|
|
1237
1296
|
|
|
1238
|
-
this.emit('list_has_after', { key, value, result:
|
|
1239
|
-
return
|
|
1297
|
+
this.emit('list_has_after', { key, value, result: 0 });
|
|
1298
|
+
return 0;
|
|
1240
1299
|
} catch (error) {
|
|
1241
1300
|
this.emit('list_has_error', { key, value, error });
|
|
1242
1301
|
$.log.error('[cachebase] list_has操作失败:', error);
|
|
@@ -1245,42 +1304,71 @@ class CacheBase extends EventEmitter {
|
|
|
1245
1304
|
}
|
|
1246
1305
|
|
|
1247
1306
|
/**
|
|
1248
|
-
* 获取列表
|
|
1307
|
+
* 获取列表 - 兼容Redis LRANGE行为
|
|
1249
1308
|
* @param {string} key - 键名
|
|
1250
|
-
* @
|
|
1309
|
+
* @param {number} start - 可选的起始索引,默认为0
|
|
1310
|
+
* @param {number} stop - 可选的结束索引,默认为-1(全部)
|
|
1311
|
+
* @returns {Promise<Array>} - 列表数据,确保始终返回数组类型
|
|
1312
|
+
* @note 兼容Redis的LRANGE命令,支持范围获取
|
|
1251
1313
|
*/
|
|
1252
|
-
async list_get(key) {
|
|
1314
|
+
async list_get(key, start = 0, stop = -1) {
|
|
1253
1315
|
try {
|
|
1254
|
-
this.emit('list_get_before', { key });
|
|
1316
|
+
this.emit('list_get_before', { key, start, stop });
|
|
1255
1317
|
|
|
1256
1318
|
// 检查键是否存在且未过期
|
|
1257
1319
|
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
1258
|
-
|
|
1259
|
-
this.
|
|
1320
|
+
// 确保返回数组类型,如果不是数组则转换为空数组
|
|
1321
|
+
const list = Array.isArray(this.data[key].value) ? [...this.data[key].value] : [];
|
|
1322
|
+
|
|
1323
|
+
// 处理Redis风格的索引范围
|
|
1324
|
+
let result = [];
|
|
1325
|
+
if (start >= 0 && stop >= -1) {
|
|
1326
|
+
if (stop === -1) {
|
|
1327
|
+
result = list.slice(start);
|
|
1328
|
+
} else {
|
|
1329
|
+
result = list.slice(start, stop + 1);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
this.emit('list_get_after', { key, start, stop, result });
|
|
1260
1334
|
return result;
|
|
1261
1335
|
}
|
|
1262
1336
|
|
|
1263
|
-
|
|
1337
|
+
// 键不存在或已过期时返回空数组
|
|
1338
|
+
this.emit('list_get_after', { key, start, stop, result: [] });
|
|
1264
1339
|
return [];
|
|
1265
1340
|
} catch (error) {
|
|
1266
|
-
this.emit('list_get_error', { key, error });
|
|
1341
|
+
this.emit('list_get_error', { key, start, stop, error });
|
|
1267
1342
|
$.log.error('[cachebase] list_get操作失败:', error);
|
|
1268
1343
|
throw error;
|
|
1269
1344
|
}
|
|
1270
1345
|
}
|
|
1271
1346
|
|
|
1272
1347
|
/**
|
|
1273
|
-
* 清空列表
|
|
1348
|
+
* 清空列表 - 兼容方法
|
|
1274
1349
|
* @param {string} key - 键名
|
|
1275
1350
|
* @returns {Promise<boolean>} - 是否成功
|
|
1351
|
+
* @note 确保操作对象始终被视为数组以保持兼容性
|
|
1276
1352
|
*/
|
|
1277
1353
|
async list_clear(key) {
|
|
1278
1354
|
try {
|
|
1279
1355
|
this.emit('list_clear_before', { key });
|
|
1280
1356
|
|
|
1281
|
-
//
|
|
1282
|
-
if (this.data.hasOwnProperty(key)
|
|
1283
|
-
//
|
|
1357
|
+
// 检查键是否存在
|
|
1358
|
+
if (this.data.hasOwnProperty(key)) {
|
|
1359
|
+
// 检查是否过期
|
|
1360
|
+
if (this.data[key].expire > 0 && Date.now() > this.data[key].expire) {
|
|
1361
|
+
// 键已过期,删除键
|
|
1362
|
+
delete this.data[key];
|
|
1363
|
+
const index = this.list.indexOf(key);
|
|
1364
|
+
if (index !== -1) {
|
|
1365
|
+
this.list.splice(index, 1);
|
|
1366
|
+
}
|
|
1367
|
+
this.emit('list_clear_after', { key, result: false });
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// 保持过期时间不变,将列表清空为[]
|
|
1284
1372
|
const expire = this.data[key].expire;
|
|
1285
1373
|
this.data[key] = {
|
|
1286
1374
|
value: [],
|
|
@@ -1291,8 +1379,19 @@ class CacheBase extends EventEmitter {
|
|
|
1291
1379
|
return true;
|
|
1292
1380
|
}
|
|
1293
1381
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1382
|
+
// 键不存在,创建一个新的空列表键
|
|
1383
|
+
this.data[key] = {
|
|
1384
|
+
value: [],
|
|
1385
|
+
expire: 0
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
// 更新列表
|
|
1389
|
+
if (!this.list.includes(key)) {
|
|
1390
|
+
this.list.push(key);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
this.emit('list_clear_after', { key, result: true });
|
|
1394
|
+
return true;
|
|
1296
1395
|
} catch (error) {
|
|
1297
1396
|
this.emit('list_clear_error', { key, error });
|
|
1298
1397
|
$.log.error('[cachebase] list_clear操作失败:', error);
|
|
@@ -1300,6 +1399,49 @@ class CacheBase extends EventEmitter {
|
|
|
1300
1399
|
}
|
|
1301
1400
|
}
|
|
1302
1401
|
|
|
1402
|
+
/**
|
|
1403
|
+
* 减少整数值(兼容Redis decr命令)
|
|
1404
|
+
* @param {string} key - 键名
|
|
1405
|
+
* @param {number} maxAge - 过期时间(秒),0表示永不过期
|
|
1406
|
+
* @returns {Promise<number>} - 减少后的值
|
|
1407
|
+
* @note 兼容Redis decr命令,初始值为0
|
|
1408
|
+
*/
|
|
1409
|
+
async decr(key, maxAge = 0) {
|
|
1410
|
+
try {
|
|
1411
|
+
this.emit('decr_before', { key, maxAge });
|
|
1412
|
+
|
|
1413
|
+
// 获取当前值或初始化为0
|
|
1414
|
+
let currentValue = 0;
|
|
1415
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
1416
|
+
const existingValue = this.data[key].value;
|
|
1417
|
+
if (typeof existingValue === 'number') {
|
|
1418
|
+
currentValue = existingValue;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// 减少1
|
|
1423
|
+
const newValue = currentValue - 1;
|
|
1424
|
+
|
|
1425
|
+
// 设置新值和过期时间
|
|
1426
|
+
this.data[key] = {
|
|
1427
|
+
value: newValue,
|
|
1428
|
+
expire: maxAge > 0 ? Date.now() + maxAge * 1000 : (this.data.hasOwnProperty(key) ? this.data[key].expire : 0)
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
// 更新列表
|
|
1432
|
+
if (!this.list.includes(key)) {
|
|
1433
|
+
this.list.push(key);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
this.emit('decr_after', { key, maxAge, result: newValue });
|
|
1437
|
+
return newValue;
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
this.emit('decr_error', { key, maxAge, error });
|
|
1440
|
+
$.log.error('[cachebase] decr操作失败:', error);
|
|
1441
|
+
throw error;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1303
1445
|
/**
|
|
1304
1446
|
* 增加浮点数(兼容方法)
|
|
1305
1447
|
* @param {string} key - 键名
|
package/package.json
CHANGED
package/test_compatibility.js
CHANGED
|
@@ -1,81 +1,109 @@
|
|
|
1
|
-
const
|
|
1
|
+
const $ = require('./index');
|
|
2
|
+
const assert = require('assert');
|
|
2
3
|
|
|
3
|
-
async function
|
|
4
|
-
console.log('
|
|
5
|
-
const cache = new CacheBase();
|
|
4
|
+
async function runTests() {
|
|
5
|
+
console.log('开始测试 CacheBase 兼容方法...');
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
|
|
7
|
+
// 创建缓存实例
|
|
8
|
+
const cache = new $.CacheBase('test_compatibility');
|
|
9
9
|
|
|
10
|
-
// list_set测试
|
|
11
|
-
console.log('\n1. list_set测试');
|
|
12
|
-
await cache.list_set('list_key', [1, 2, 3]);
|
|
13
|
-
const list1 = await cache.list_get('list_key');
|
|
14
|
-
console.log(`list_set('list_key', [1, 2, 3]) 后的值:`, list1);
|
|
15
|
-
|
|
16
|
-
// list_add测试
|
|
17
|
-
console.log('\n2. list_add测试');
|
|
18
|
-
await cache.list_add('list_key', 4);
|
|
19
|
-
const list2 = await cache.list_get('list_key');
|
|
20
|
-
console.log(`list_add('list_key', 4) 后的值:`, list2);
|
|
21
|
-
|
|
22
|
-
// list_has测试
|
|
23
|
-
console.log('\n3. list_has测试');
|
|
24
|
-
const has2 = await cache.list_has('list_key', 2);
|
|
25
|
-
const has5 = await cache.list_has('list_key', 5);
|
|
26
|
-
console.log(`list_has('list_key', 2):`, has2);
|
|
27
|
-
console.log(`list_has('list_key', 5):`, has5);
|
|
28
|
-
|
|
29
|
-
// list_get测试
|
|
30
|
-
console.log('\n4. list_get测试');
|
|
31
|
-
const list3 = await cache.list_get('list_key');
|
|
32
|
-
console.log(`list_get('list_key'):`, list3);
|
|
33
|
-
|
|
34
|
-
// list_clear测试
|
|
35
|
-
console.log('\n5. list_clear测试');
|
|
36
|
-
await cache.list_clear('list_key');
|
|
37
|
-
const list4 = await cache.list_get('list_key');
|
|
38
|
-
console.log(`list_clear('list_key') 后的值:`, list4);
|
|
39
|
-
|
|
40
|
-
// 测试add方法
|
|
41
|
-
console.log('\n===== 测试add方法 =====');
|
|
42
|
-
|
|
43
|
-
// 重置缓存
|
|
44
|
-
await cache.clear();
|
|
45
|
-
|
|
46
|
-
// 测试1: 键不存在时设置数值
|
|
47
|
-
console.log('\n1. 键不存在时设置数值');
|
|
48
|
-
const result1 = await cache.add('num_key', 10);
|
|
49
|
-
console.log(`add('num_key', 10) =`, result1);
|
|
50
|
-
console.log(`get('num_key') =`, await cache.get('num_key'));
|
|
51
|
-
|
|
52
|
-
// 测试2: 键存在时增加值
|
|
53
|
-
console.log('\n2. 键存在时增加值');
|
|
54
|
-
const result2 = await cache.add('num_key', 5);
|
|
55
|
-
console.log(`add('num_key', 5) =`, result2);
|
|
56
|
-
console.log(`get('num_key') =`, await cache.get('num_key'));
|
|
57
|
-
|
|
58
|
-
// 测试3: 字符串形式的数字
|
|
59
|
-
console.log('\n3. 字符串形式的数字');
|
|
60
|
-
const result3 = await cache.add('num_key2', '123');
|
|
61
|
-
console.log(`add('num_key2', '123') =`, result3);
|
|
62
|
-
console.log(`get('num_key2') =`, await cache.get('num_key2'));
|
|
63
|
-
|
|
64
|
-
// 测试4: 非数值字符串(应该抛出错误)
|
|
65
|
-
console.log('\n4. 非数值字符串');
|
|
66
10
|
try {
|
|
67
|
-
|
|
11
|
+
// 测试 list_* 方法
|
|
12
|
+
console.log('\n=== 测试 list_* 方法 ===');
|
|
13
|
+
|
|
14
|
+
// 测试 list_set - 确保值始终是数组类型
|
|
15
|
+
await cache.list_set('list1', 'single value');
|
|
16
|
+
let result = await cache.list_get('list1');
|
|
17
|
+
console.log('list_set 单值测试:', Array.isArray(result), result);
|
|
18
|
+
assert.strictEqual(Array.isArray(result), true, 'list_set 应确保值是数组类型');
|
|
19
|
+
assert.strictEqual(result.length, 1, 'list_set 应将单值包装成数组');
|
|
20
|
+
|
|
21
|
+
// 测试 list_set - 数组值
|
|
22
|
+
await cache.list_set('list2', [1, 2, 3]);
|
|
23
|
+
result = await cache.list_get('list2');
|
|
24
|
+
console.log('list_set 数组测试:', Array.isArray(result), result);
|
|
25
|
+
assert.strictEqual(Array.isArray(result), true, 'list_set 应保持数组类型');
|
|
26
|
+
assert.strictEqual(result.length, 3, 'list_set 应正确存储数组');
|
|
27
|
+
|
|
28
|
+
// 测试 list_add - 向空列表添加
|
|
29
|
+
await cache.list_add('list3', 'item1');
|
|
30
|
+
result = await cache.list_get('list3');
|
|
31
|
+
console.log('list_add 空列表测试:', result);
|
|
32
|
+
assert.strictEqual(result.length, 1, 'list_add 应向空列表添加元素');
|
|
33
|
+
|
|
34
|
+
// 测试 list_add - 向现有列表添加
|
|
35
|
+
await cache.list_add('list3', 'item2');
|
|
36
|
+
result = await cache.list_get('list3');
|
|
37
|
+
console.log('list_add 现有列表测试:', result);
|
|
38
|
+
assert.strictEqual(result.length, 2, 'list_add 应向现有列表添加元素');
|
|
39
|
+
|
|
40
|
+
// 测试 list_has - 基本类型
|
|
41
|
+
let hasValue = await cache.list_has('list3', 'item1');
|
|
42
|
+
console.log('list_has 基本类型测试:', hasValue);
|
|
43
|
+
assert.strictEqual(hasValue, true, 'list_has 应正确检测基本类型');
|
|
44
|
+
|
|
45
|
+
// 测试 list_has - 对象类型
|
|
46
|
+
const objValue = { name: 'test', value: 123 };
|
|
47
|
+
await cache.list_add('list4', objValue);
|
|
48
|
+
hasValue = await cache.list_has('list4', { name: 'test', value: 123 });
|
|
49
|
+
console.log('list_has 对象类型测试:', hasValue);
|
|
50
|
+
assert.strictEqual(hasValue, true, 'list_has 应正确检测对象类型');
|
|
51
|
+
|
|
52
|
+
// 测试 list_clear - 清空现有列表
|
|
53
|
+
result = await cache.list_clear('list3');
|
|
54
|
+
console.log('list_clear 现有列表测试:', result);
|
|
55
|
+
assert.strictEqual(result, true, 'list_clear 应对现有列表返回 true');
|
|
56
|
+
result = await cache.list_get('list3');
|
|
57
|
+
assert.strictEqual(Array.isArray(result), true, 'list_clear 后应返回数组');
|
|
58
|
+
assert.strictEqual(result.length, 0, 'list_clear 应清空列表');
|
|
59
|
+
|
|
60
|
+
// 测试 list_clear - 不存在的键
|
|
61
|
+
result = await cache.list_clear('nonexistent_list');
|
|
62
|
+
console.log('list_clear 不存在键测试:', result);
|
|
63
|
+
assert.strictEqual(result, true, 'list_clear 应对不存在的键创建空列表并返回 true');
|
|
64
|
+
result = await cache.list_get('nonexistent_list');
|
|
65
|
+
assert.strictEqual(Array.isArray(result), true, 'list_clear 后应创建空数组');
|
|
66
|
+
|
|
67
|
+
// 测试 hdel 方法
|
|
68
|
+
console.log('\n=== 测试 hdel 方法 ===');
|
|
69
|
+
|
|
70
|
+
// 创建哈希表
|
|
71
|
+
await cache.hset('hash1', 'field1', 'value1');
|
|
72
|
+
await cache.hset('hash1', 'field2', 'value2');
|
|
73
|
+
|
|
74
|
+
// 测试 hdel - 存在的字段
|
|
75
|
+
result = await cache.hdel('hash1', 'field1');
|
|
76
|
+
console.log('hdel 存在字段测试:', result);
|
|
77
|
+
assert.strictEqual(result, 0, 'hdel 应始终返回 0 以保持兼容性');
|
|
78
|
+
|
|
79
|
+
// 验证字段已被删除
|
|
80
|
+
let hashValue = await cache.hget('hash1', 'field1');
|
|
81
|
+
assert.strictEqual(hashValue, undefined, 'hdel 应实际删除字段');
|
|
82
|
+
|
|
83
|
+
// 测试 hdel - 不存在的字段
|
|
84
|
+
result = await cache.hdel('hash1', 'nonexistent_field');
|
|
85
|
+
console.log('hdel 不存在字段测试:', result);
|
|
86
|
+
assert.strictEqual(result, 0, 'hdel 应对不存在的字段返回 0');
|
|
87
|
+
|
|
88
|
+
// 测试 hdel - 不存在的键
|
|
89
|
+
result = await cache.hdel('nonexistent_hash', 'field');
|
|
90
|
+
console.log('hdel 不存在键测试:', result);
|
|
91
|
+
assert.strictEqual(result, 0, 'hdel 应对不存在的键返回 0');
|
|
92
|
+
|
|
93
|
+
console.log('\n所有测试通过!');
|
|
68
94
|
} catch (error) {
|
|
69
|
-
console.
|
|
95
|
+
console.error('测试失败:', error.message);
|
|
96
|
+
throw error;
|
|
97
|
+
} finally {
|
|
98
|
+
// 清理测试数据
|
|
99
|
+
await cache.clear();
|
|
100
|
+
await cache.dispose();
|
|
101
|
+
console.log('\n测试完成,已清理数据');
|
|
70
102
|
}
|
|
71
|
-
|
|
72
|
-
// 测试5: 带过期时间
|
|
73
|
-
console.log('\n5. 带过期时间');
|
|
74
|
-
const result5 = await cache.add('num_key4', 100, 3); // 3秒过期
|
|
75
|
-
console.log(`add('num_key4', 100, 3) =`, result5);
|
|
76
|
-
console.log(`ttl('num_key4') =`, await cache.ttl('num_key4'));
|
|
77
|
-
|
|
78
|
-
console.log('\n所有方法兼容性测试完成!');
|
|
79
103
|
}
|
|
80
104
|
|
|
81
|
-
|
|
105
|
+
// 运行测试
|
|
106
|
+
runTests().catch(error => {
|
|
107
|
+
console.error('测试执行失败:', error);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { CacheBase } = require('./index');
|
|
3
|
+
async function testCompatibility() {
|
|
4
|
+
console.log('开始测试兼容性改进...');
|
|
5
|
+
|
|
6
|
+
// 创建缓存实例
|
|
7
|
+
const cache = new CacheBase('test_compatibility');
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
// 清空之前的测试数据
|
|
11
|
+
await cache.clear();
|
|
12
|
+
|
|
13
|
+
console.log('\n1. 测试 set 方法兼容性');
|
|
14
|
+
// 测试set方法
|
|
15
|
+
const setResult = await cache.set('test_key', 'test_value');
|
|
16
|
+
assert.strictEqual(setResult, 'OK', 'set方法应返回OK');
|
|
17
|
+
const getResult = await cache.get('test_key');
|
|
18
|
+
assert.strictEqual(getResult, 'test_value', 'set方法设置的值应正确');
|
|
19
|
+
console.log('✓ set 方法测试通过');
|
|
20
|
+
|
|
21
|
+
console.log('\n2. 测试 del 方法兼容性');
|
|
22
|
+
// 测试del方法删除存在的键
|
|
23
|
+
const delResult1 = await cache.del('test_key');
|
|
24
|
+
assert.strictEqual(delResult1, 1, 'del方法应返回删除的键数量1');
|
|
25
|
+
const exists1 = await cache.exists('test_key');
|
|
26
|
+
assert.strictEqual(exists1, 0, '删除的键不应再存在');
|
|
27
|
+
|
|
28
|
+
// 测试del方法删除不存在的键
|
|
29
|
+
const delResult2 = await cache.del('non_existent_key');
|
|
30
|
+
assert.strictEqual(delResult2, 0, '删除不存在的键应返回0');
|
|
31
|
+
console.log('✓ del 方法测试通过');
|
|
32
|
+
|
|
33
|
+
console.log('\n3. 测试 exists 方法兼容性');
|
|
34
|
+
// 设置一些测试键
|
|
35
|
+
await cache.set('exists_key1', 'value1');
|
|
36
|
+
await cache.set('exists_key2', 'value2', 1); // 1秒过期
|
|
37
|
+
|
|
38
|
+
// 测试单个键存在
|
|
39
|
+
const existsResult1 = await cache.exists('exists_key1');
|
|
40
|
+
assert.strictEqual(existsResult1, 1, 'exists方法应返回存在的键数量1');
|
|
41
|
+
|
|
42
|
+
// 测试多个键存在
|
|
43
|
+
const existsResult2 = await cache.exists(['exists_key1', 'exists_key2', 'non_existent']);
|
|
44
|
+
assert.strictEqual(existsResult2, 2, 'exists方法应返回存在的键数量2');
|
|
45
|
+
|
|
46
|
+
// 测试不存在的键
|
|
47
|
+
const existsResult3 = await cache.exists('non_existent');
|
|
48
|
+
assert.strictEqual(existsResult3, 0, '不存在的键应返回0');
|
|
49
|
+
console.log('✓ exists 方法测试通过');
|
|
50
|
+
|
|
51
|
+
console.log('\n4. 测试 ttl 方法兼容性');
|
|
52
|
+
// 设置带过期时间的键
|
|
53
|
+
await cache.set('ttl_key', 'ttl_value', 10); // 10秒过期
|
|
54
|
+
|
|
55
|
+
// 测试永不过期的键
|
|
56
|
+
await cache.set('ttl_key_forever', 'forever_value');
|
|
57
|
+
const ttlForever = await cache.ttl('ttl_key_forever');
|
|
58
|
+
assert.strictEqual(ttlForever, -1, '永不过期的键ttl应返回-1');
|
|
59
|
+
|
|
60
|
+
// 测试存在但已过期的键
|
|
61
|
+
await cache.set('ttl_key_expire', 'expire_value', 1); // 1秒过期
|
|
62
|
+
await new Promise(resolve => setTimeout(resolve, 1500)); // 等待过期
|
|
63
|
+
const ttlExpired = await cache.ttl('ttl_key_expire');
|
|
64
|
+
assert.strictEqual(ttlExpired, -2, '已过期的键ttl应返回-2');
|
|
65
|
+
|
|
66
|
+
// 测试不存在的键
|
|
67
|
+
const ttlNonExistent = await cache.ttl('non_existent_ttl');
|
|
68
|
+
assert.strictEqual(ttlNonExistent, -2, '不存在的键ttl应返回-2');
|
|
69
|
+
|
|
70
|
+
// 测试有过期时间的键
|
|
71
|
+
await cache.set('ttl_key_with_ttl', 'value_with_ttl', 2); // 2秒过期
|
|
72
|
+
const ttlWithTtl = await cache.ttl('ttl_key_with_ttl');
|
|
73
|
+
assert.ok(ttlWithTtl >= 0 && ttlWithTtl <= 2, '有过期时间的键应返回剩余秒数');
|
|
74
|
+
console.log('✓ ttl 方法测试通过');
|
|
75
|
+
|
|
76
|
+
console.log('\n5. 测试 clear 方法兼容性');
|
|
77
|
+
// 设置一些测试键
|
|
78
|
+
await cache.set('clear_key1', 'value1');
|
|
79
|
+
await cache.set('clear_key2', 'value2');
|
|
80
|
+
await cache.set('test_pattern1', 'pattern1');
|
|
81
|
+
await cache.set('test_pattern2', 'pattern2');
|
|
82
|
+
|
|
83
|
+
// 测试模式匹配清除
|
|
84
|
+
await cache.clear('test_pattern*');
|
|
85
|
+
const existsPattern1 = await cache.exists('test_pattern1');
|
|
86
|
+
const existsPattern2 = await cache.exists('test_pattern2');
|
|
87
|
+
const existsClear1 = await cache.exists('clear_key1');
|
|
88
|
+
assert.strictEqual(existsPattern1, 0, '模式匹配的键应被清除');
|
|
89
|
+
assert.strictEqual(existsPattern2, 0, '模式匹配的键应被清除');
|
|
90
|
+
assert.strictEqual(existsClear1, 1, '非模式匹配的键应保留');
|
|
91
|
+
|
|
92
|
+
// 测试全部清除
|
|
93
|
+
await cache.clear();
|
|
94
|
+
const existsAfterClear = await cache.exists(['clear_key1', 'clear_key2']);
|
|
95
|
+
assert.strictEqual(existsAfterClear, 0, 'clear方法应清除所有键');
|
|
96
|
+
console.log('✓ clear 方法测试通过');
|
|
97
|
+
|
|
98
|
+
// 新添加的测试:addInt、addStr、addFloat、mset、mget
|
|
99
|
+
console.log('\n6. 测试 addInt 方法兼容性');
|
|
100
|
+
const intResult1 = await cache.addInt('int_key', 10);
|
|
101
|
+
assert.strictEqual(intResult1, 10, 'addInt初始值应为10');
|
|
102
|
+
const intResult2 = await cache.addInt('int_key', 5);
|
|
103
|
+
assert.strictEqual(intResult2, 15, 'addInt增加后应为15');
|
|
104
|
+
console.log('✓ addInt 方法测试通过');
|
|
105
|
+
|
|
106
|
+
console.log('\n7. 测试 addStr 方法兼容性');
|
|
107
|
+
const strResult1 = await cache.addStr('str_key', 'hello');
|
|
108
|
+
assert.strictEqual(strResult1, 5, '初始字符串长度应为5');
|
|
109
|
+
const strResult2 = await cache.addStr('str_key', ' world');
|
|
110
|
+
assert.strictEqual(strResult2, 11, '追加后字符串长度应为11');
|
|
111
|
+
console.log('✓ addStr 方法测试通过');
|
|
112
|
+
|
|
113
|
+
console.log('\n8. 测试 addFloat 方法兼容性');
|
|
114
|
+
const floatResult1 = await cache.addFloat('float_key', 10.5);
|
|
115
|
+
assert.strictEqual(floatResult1, 10.5, '初始浮点数应为10.5');
|
|
116
|
+
const floatResult2 = await cache.addFloat('float_key', 2.5);
|
|
117
|
+
assert.strictEqual(floatResult2, 13.0, '增加后浮点数应为13.0');
|
|
118
|
+
console.log('✓ addFloat 方法测试通过');
|
|
119
|
+
|
|
120
|
+
console.log('\n9. 测试 mset 方法兼容性');
|
|
121
|
+
const msetResult = await cache.mset({ mkey1: 'value1', mkey2: 'value2' });
|
|
122
|
+
assert.strictEqual(msetResult, 'OK', 'mset应返回OK');
|
|
123
|
+
assert.strictEqual(await cache.get('mkey1'), 'value1', 'mset应正确设置值1');
|
|
124
|
+
assert.strictEqual(await cache.get('mkey2'), 'value2', 'mset应正确设置值2');
|
|
125
|
+
console.log('✓ mset 方法测试通过');
|
|
126
|
+
|
|
127
|
+
console.log('\n10. 测试 mget 方法兼容性');
|
|
128
|
+
const mgetResult = await cache.mget(['mkey1', 'mkey2', 'nonexistent']);
|
|
129
|
+
assert.deepStrictEqual(mgetResult, ['value1', 'value2', undefined], 'mget应正确获取多个值');
|
|
130
|
+
console.log('✓ mget 方法测试通过');
|
|
131
|
+
|
|
132
|
+
console.log('\n所有兼容性测试通过!');
|
|
133
|
+
return true;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error('测试失败:', error);
|
|
136
|
+
return false;
|
|
137
|
+
} finally {
|
|
138
|
+
// 清理测试数据
|
|
139
|
+
await cache.clear();
|
|
140
|
+
await cache.save();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 运行测试
|
|
145
|
+
testCompatibility().then(success => {
|
|
146
|
+
process.exit(success ? 0 : 1);
|
|
147
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { CacheBase } = require('./index');
|
|
3
|
+
async function testCompatibilityImprovements() {
|
|
4
|
+
console.log('开始测试兼容性改进方法...');
|
|
5
|
+
|
|
6
|
+
// 创建缓存实例
|
|
7
|
+
const cache = new CacheBase('test_compatibility_methods');
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
// 清空之前的测试数据
|
|
11
|
+
await cache.clear();
|
|
12
|
+
|
|
13
|
+
console.log('\n1. 测试 decr 方法兼容性');
|
|
14
|
+
// 测试decr方法初始值
|
|
15
|
+
const decrResult1 = await cache.decr('decr_key');
|
|
16
|
+
assert.strictEqual(decrResult1, -1, 'decr初始值应为-1');
|
|
17
|
+
|
|
18
|
+
// 测试decr方法增加值
|
|
19
|
+
const decrResult2 = await cache.decr('decr_key');
|
|
20
|
+
assert.strictEqual(decrResult2, -2, 'decr减少后应为-2');
|
|
21
|
+
|
|
22
|
+
// 测试已有数值的decr
|
|
23
|
+
await cache.set('decr_existing', 5);
|
|
24
|
+
const decrResult3 = await cache.decr('decr_existing');
|
|
25
|
+
assert.strictEqual(decrResult3, 4, '现有数值decr后应为4');
|
|
26
|
+
console.log('✓ decr 方法测试通过');
|
|
27
|
+
|
|
28
|
+
console.log('\n2. 测试 list_set 方法兼容性');
|
|
29
|
+
// 测试list_set返回列表长度
|
|
30
|
+
const listSetResult1 = await cache.list_set('list_key', ['item1', 'item2']);
|
|
31
|
+
assert.strictEqual(listSetResult1, 2, 'list_set应返回列表长度');
|
|
32
|
+
|
|
33
|
+
// 测试非数组值
|
|
34
|
+
const listSetResult2 = await cache.list_set('list_key_single', 'single_item');
|
|
35
|
+
assert.strictEqual(listSetResult2, 1, '非数组值list_set应返回1');
|
|
36
|
+
const listContent = await cache.list_get('list_key_single');
|
|
37
|
+
assert.deepStrictEqual(listContent, ['single_item'], '非数组值应被包装为数组');
|
|
38
|
+
console.log('✓ list_set 方法测试通过');
|
|
39
|
+
|
|
40
|
+
console.log('\n3. 测试 list_add 方法兼容性');
|
|
41
|
+
// 测试list_add返回列表长度
|
|
42
|
+
await cache.list_set('add_list', ['initial']);
|
|
43
|
+
const listAddResult1 = await cache.list_add('add_list', 'new_item');
|
|
44
|
+
assert.strictEqual(listAddResult1, 2, 'list_add应返回添加后列表长度');
|
|
45
|
+
|
|
46
|
+
// 测试空列表添加
|
|
47
|
+
const listAddResult2 = await cache.list_add('new_list', 'first_item');
|
|
48
|
+
assert.strictEqual(listAddResult2, 1, '空列表添加应返回1');
|
|
49
|
+
console.log('✓ list_add 方法测试通过');
|
|
50
|
+
|
|
51
|
+
console.log('\n4. 测试 list_has 方法兼容性');
|
|
52
|
+
// 设置测试列表
|
|
53
|
+
await cache.list_set('has_list', ['item1', 'item2', 'item3']);
|
|
54
|
+
|
|
55
|
+
// 测试存在的项
|
|
56
|
+
const hasResult1 = await cache.list_has('has_list', 'item2');
|
|
57
|
+
assert.strictEqual(hasResult1, 1, '存在的项应返回1');
|
|
58
|
+
|
|
59
|
+
// 测试不存在的项
|
|
60
|
+
const hasResult2 = await cache.list_has('has_list', 'item4');
|
|
61
|
+
assert.strictEqual(hasResult2, 0, '不存在的项应返回0');
|
|
62
|
+
|
|
63
|
+
// 测试不存在的键
|
|
64
|
+
const hasResult3 = await cache.list_has('non_existent_list', 'anything');
|
|
65
|
+
assert.strictEqual(hasResult3, 0, '不存在的键应返回0');
|
|
66
|
+
console.log('✓ list_has 方法测试通过');
|
|
67
|
+
|
|
68
|
+
console.log('\n5. 测试 list_get 方法兼容性');
|
|
69
|
+
// 设置测试列表
|
|
70
|
+
await cache.list_set('range_list', ['item0', 'item1', 'item2', 'item3', 'item4']);
|
|
71
|
+
|
|
72
|
+
// 测试全量获取
|
|
73
|
+
const getResult1 = await cache.list_get('range_list');
|
|
74
|
+
assert.deepStrictEqual(getResult1, ['item0', 'item1', 'item2', 'item3', 'item4'], '默认应返回全部元素');
|
|
75
|
+
|
|
76
|
+
// 测试范围获取
|
|
77
|
+
const getResult2 = await cache.list_get('range_list', 1, 3);
|
|
78
|
+
assert.deepStrictEqual(getResult2, ['item1', 'item2', 'item3'], '范围获取应返回指定元素');
|
|
79
|
+
|
|
80
|
+
// 测试起始索引获取
|
|
81
|
+
const getResult3 = await cache.list_get('range_list', 2);
|
|
82
|
+
assert.deepStrictEqual(getResult3, ['item2', 'item3', 'item4'], '只指定起始索引应返回从该索引到末尾');
|
|
83
|
+
|
|
84
|
+
// 测试不存在的键
|
|
85
|
+
const getResult4 = await cache.list_get('non_existent_range');
|
|
86
|
+
assert.deepStrictEqual(getResult4, [], '不存在的键应返回空数组');
|
|
87
|
+
console.log('✓ list_get 方法测试通过');
|
|
88
|
+
|
|
89
|
+
// 清理测试数据
|
|
90
|
+
await cache.clear();
|
|
91
|
+
console.log('\n所有兼容性改进方法测试通过!');
|
|
92
|
+
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('兼容性改进方法测试失败:', error);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
testCompatibilityImprovements();
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { CacheBase } = require('./index');
|
|
3
|
+
|
|
4
|
+
async function testUndocumentedMethods() {
|
|
5
|
+
console.log('开始测试文档与实现不一致的方法...');
|
|
6
|
+
|
|
7
|
+
// 创建缓存实例
|
|
8
|
+
const cache = new CacheBase('test_undocumented');
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
// 清空之前的测试数据
|
|
12
|
+
await cache.clear();
|
|
13
|
+
|
|
14
|
+
console.log('\n1. 测试 addInt 方法');
|
|
15
|
+
const intResult1 = await cache.addInt('int_key', 10);
|
|
16
|
+
assert.strictEqual(intResult1, 10, 'addInt初始值应为10');
|
|
17
|
+
const intResult2 = await cache.addInt('int_key', 5);
|
|
18
|
+
assert.strictEqual(intResult2, 15, 'addInt增加后应为15');
|
|
19
|
+
console.log('✓ addInt 方法测试通过');
|
|
20
|
+
|
|
21
|
+
console.log('\n2. 测试 addStr 方法');
|
|
22
|
+
const strResult1 = await cache.addStr('str_key', 'hello');
|
|
23
|
+
assert.strictEqual(strResult1, 5, '初始字符串长度应为5');
|
|
24
|
+
const strResult2 = await cache.addStr('str_key', ' world');
|
|
25
|
+
assert.strictEqual(strResult2, 11, '追加后字符串长度应为11');
|
|
26
|
+
console.log('✓ addStr 方法测试通过');
|
|
27
|
+
|
|
28
|
+
console.log('\n3. 测试 addFloat 方法');
|
|
29
|
+
const floatResult1 = await cache.addFloat('float_key', 10.5);
|
|
30
|
+
assert.strictEqual(floatResult1, 10.5, '初始浮点数应为10.5');
|
|
31
|
+
const floatResult2 = await cache.addFloat('float_key', 2.5);
|
|
32
|
+
assert.strictEqual(floatResult2, 13.0, '增加后浮点数应为13.0');
|
|
33
|
+
console.log('✓ addFloat 方法测试通过');
|
|
34
|
+
|
|
35
|
+
console.log('\n4. 测试 mset 方法');
|
|
36
|
+
const msetResult = await cache.mset({ mkey1: 'value1', mkey2: 'value2' });
|
|
37
|
+
assert.strictEqual(msetResult, 'OK', 'mset应返回OK');
|
|
38
|
+
assert.strictEqual(await cache.get('mkey1'), 'value1', 'mset应正确设置值1');
|
|
39
|
+
assert.strictEqual(await cache.get('mkey2'), 'value2', 'mset应正确设置值2');
|
|
40
|
+
console.log('✓ mset 方法测试通过');
|
|
41
|
+
|
|
42
|
+
console.log('\n5. 测试 mget 方法');
|
|
43
|
+
const mgetResult = await cache.mget(['mkey1', 'mkey2', 'nonexistent']);
|
|
44
|
+
assert.deepStrictEqual(mgetResult, ['value1', 'value2', undefined], 'mget应正确获取多个值');
|
|
45
|
+
console.log('✓ mget 方法测试通过');
|
|
46
|
+
|
|
47
|
+
// 清理测试数据
|
|
48
|
+
await cache.clear();
|
|
49
|
+
console.log('\n所有测试通过!');
|
|
50
|
+
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('测试失败:', error);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
testUndocumentedMethods();
|