mm_cachebase 1.8.4 → 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 -159
- package/index.js +130 -45
- package/package.json +1 -1
- 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,176 +23,79 @@
|
|
|
27
23
|
|-------|-------|---------|-----------|--------|----------|
|
|
28
24
|
| hset | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
29
25
|
| hget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
|
|
30
|
-
| hgetall | ✅ | ✅ | ✅ | ✅ |
|
|
31
|
-
| hdel |
|
|
32
|
-
| hmset | ✅ | ✅ |
|
|
33
|
-
| hmget |
|
|
34
|
-
| hlen | ✅ | ✅ |
|
|
26
|
+
| hgetall | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
27
|
+
| hdel | ✅ | ✅ | ✅ | ✅ | 所有方式都支持 |
|
|
28
|
+
| hmset | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
29
|
+
| hmget | ❌ | ✅ | ❌ | ❌ | 仅MongoDB支持 |
|
|
30
|
+
| hlen | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
35
31
|
|
|
36
32
|
## Redis兼容方法 - 其他常用命令
|
|
37
33
|
|
|
38
34
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
39
35
|
|-------|-------|---------|-----------|--------|----------|
|
|
40
|
-
| expire | ✅ | ✅ | ✅ | ✅ |
|
|
41
|
-
| incr | ✅ | ✅ | ✅ | ✅ |
|
|
42
|
-
| decr | ✅ |
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| type |
|
|
50
|
-
| 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 | ❌ | ❌ | ❌ | ❌ | 所有方式都不支持 |
|
|
51
47
|
|
|
52
48
|
## Redis兼容方法 - 集合操作
|
|
53
49
|
|
|
54
50
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
55
51
|
|-------|-------|---------|-----------|--------|----------|
|
|
56
|
-
| sadd | ✅ |
|
|
57
|
-
| srem | ✅ |
|
|
58
|
-
| sismember | ✅ | ✅ |
|
|
59
|
-
| smembers | ✅ | ✅ |
|
|
52
|
+
| sadd | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
53
|
+
| srem | ✅ | ❌ | ❌ | ❌ | 仅Redis支持 |
|
|
54
|
+
| sismember | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
55
|
+
| smembers | ✅ | ✅ | ❌ | ❌ | Redis和MongoDB支持,其他方式不支持 |
|
|
60
56
|
|
|
61
57
|
## 数组/列表操作方法
|
|
62
58
|
|
|
63
59
|
| 方法名 | Redis | MongoDB | CacheBase | Memory | 状态说明 |
|
|
64
60
|
|-------|-------|---------|-----------|--------|----------|
|
|
65
|
-
| list_set | ✅ |
|
|
66
|
-
| list_add | ✅ |
|
|
67
|
-
| list_has | ✅ |
|
|
68
|
-
| list_get | ✅ |
|
|
69
|
-
| 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不支持,其他方式支持 |
|
|
70
66
|
|
|
71
67
|
## 兼容性报告总结
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
基于实际功能测试,以下是四种缓存方式的兼容性报告:
|
|
74
70
|
|
|
75
71
|
| 方法类别 | CacheBase | Redis | MongoDB | Memory | 状态说明 |
|
|
76
72
|
|---------|-----------|-------|---------|--------|----------|
|
|
77
|
-
| 基础键值操作 | ✅ | ✅ | ✅ | ✅ |
|
|
78
|
-
| 数组操作 |
|
|
79
|
-
| 过期时间操作 | ✅ | ✅ | ✅ | ✅ |
|
|
80
|
-
| 原子递增操作 | ✅ | ✅ | ✅ | ✅ |
|
|
81
|
-
| 批量操作 | ✅ | ✅ | ✅ | ✅ |
|
|
82
|
-
| 哈希表基本操作 |
|
|
83
|
-
| 哈希表批量操作 |
|
|
84
|
-
| 集合操作 |
|
|
85
|
-
| 字符串操作 | ✅ | ✅ |
|
|
86
|
-
| 类型检测 |
|
|
87
|
-
| 键重命名 |
|
|
88
|
-
| 清理操作 | ✅ | ✅ | ✅ | ✅ |
|
|
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操作正常工作 |
|
|
89
85
|
|
|
90
86
|
### 测试统计
|
|
91
87
|
|
|
92
|
-
- **总测试用例**:
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- **键重命名**:rename
|
|
107
|
-
- **清理操作**:clear
|
|
108
|
-
- **数组操作**:list_set, list_add, list_has, list_get, list_clear (通过通用实现)
|
|
109
|
-
|
|
110
|
-
### CacheBase 缓存方式:
|
|
111
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
112
|
-
- **兼容性**:完全兼容Redis接口
|
|
113
|
-
- **返回值**:所有操作都返回符合预期的结果
|
|
114
|
-
- **优点**:无需外部依赖,性能优秀,返回值一致性高,支持持久化
|
|
115
|
-
|
|
116
|
-
### MongoDB 缓存方式:
|
|
117
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
118
|
-
- **兼容性**:完全兼容Redis接口
|
|
119
|
-
- **返回值**:所有操作都返回正确的结果,包括incr/decr返回数值,mget返回正确的结果数组
|
|
120
|
-
- **优点**:支持持久化存储,重启后数据不会丢失
|
|
121
|
-
|
|
122
|
-
### Redis 缓存方式:
|
|
123
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
124
|
-
- **通过率**:100%
|
|
125
|
-
- **优点**:支持持久化存储,重启后数据不会丢失,支持分布式缓存
|
|
126
|
-
- **注意事项**:已修复认证配置问题,现在可以正常使用
|
|
127
|
-
|
|
128
|
-
### Memory 缓存方式:
|
|
129
|
-
- **测试状态**:✅ 所有12个方法类别测试通过
|
|
130
|
-
- **兼容性**:完全兼容Redis接口
|
|
131
|
-
- **优点**:最高性能,纯内存操作,无I/O开销
|
|
132
|
-
- **缺点**:不支持持久化,程序重启后数据会丢失
|
|
133
|
-
|
|
134
|
-
### 已确认移除的方法:
|
|
135
|
-
- hexists:测试中报错 "TypeError: cache.hexists is not a function"
|
|
136
|
-
- hkeys、hvals:已移除
|
|
137
|
-
|
|
138
|
-
## 最佳使用建议
|
|
139
|
-
|
|
140
|
-
1. **Memory 方式**(推荐用于内存临时缓存):
|
|
141
|
-
- 所有功能完全兼容,返回值符合预期
|
|
142
|
-
- 性能最优,纯内存操作无I/O开销
|
|
143
|
-
- 适合短期缓存、临时数据缓存场景
|
|
144
|
-
- 不需要额外的外部服务依赖
|
|
145
|
-
- 程序重启后数据会丢失
|
|
146
|
-
|
|
147
|
-
2. **CacheBase 方式**(推荐用于单机持久化缓存):
|
|
148
|
-
- 所有功能完全兼容,返回值符合预期
|
|
149
|
-
- 性能稳定,在多次依赖更新中保持一致表现
|
|
150
|
-
- 适合需要持久化但不需要分布式的场景
|
|
151
|
-
- 不需要额外的外部服务依赖
|
|
152
|
-
- 程序重启后数据不会丢失
|
|
153
|
-
|
|
154
|
-
3. **Redis 方式**(推荐用于分布式持久化缓存):
|
|
155
|
-
- 已完全修复所有兼容性问题
|
|
156
|
-
- 支持分布式缓存,数据可在多实例间共享
|
|
157
|
-
- 适合需要高性能、分布式缓存或Redis特有功能的场景
|
|
158
|
-
- 需要外部Redis服务
|
|
159
|
-
- 程序重启后数据不会丢失
|
|
160
|
-
|
|
161
|
-
4. **MongoDB 方式**(推荐用于已有MongoDB环境的场景):
|
|
162
|
-
- 所有方法均完全兼容Redis接口
|
|
163
|
-
- 所有操作都返回正确的结果,包括incr/decr和mget
|
|
164
|
-
- 适合需要持久化缓存且已有MongoDB环境的场景
|
|
165
|
-
- 提供了数据持久化保障
|
|
166
|
-
- 需要外部MongoDB服务
|
|
167
|
-
- 程序重启后数据不会丢失
|
|
168
|
-
|
|
169
|
-
## 实际使用建议
|
|
170
|
-
|
|
171
|
-
1. **开发环境**:推荐使用Memory或CacheBase,无需额外配置,使用简单
|
|
172
|
-
|
|
173
|
-
2. **生产环境**:
|
|
174
|
-
- 如果需要极致性能且数据不敏感:使用Memory
|
|
175
|
-
- 如果需要单机持久化:使用CacheBase
|
|
176
|
-
- 如果需要高性能、分布式缓存:使用Redis
|
|
177
|
-
- 如果需要缓存持久化且已有MongoDB环境:使用MongoDB
|
|
178
|
-
|
|
179
|
-
3. **跨环境部署**:
|
|
180
|
-
- 可以根据环境配置自动切换缓存方式
|
|
181
|
-
- 所有缓存方式的返回值特性一致,可以放心切换
|
|
182
|
-
|
|
183
|
-
4. **性能考虑**:
|
|
184
|
-
- Memory:纯内存操作,最快但不持久化
|
|
185
|
-
- CacheBase:文件系统操作,性能优秀且支持持久化
|
|
186
|
-
- Redis:网络操作,但性能优秀,支持持久化和分布式
|
|
187
|
-
- MongoDB:网络+磁盘操作,性能相对较低但支持持久化
|
|
188
|
-
|
|
189
|
-
## 兼容性维护建议
|
|
190
|
-
|
|
191
|
-
1. **文档维护**:
|
|
192
|
-
- 更新README.md,明确标注支持的方法和各缓存方式的特点
|
|
193
|
-
|
|
194
|
-
2. **测试维护**:
|
|
195
|
-
- 保留test.js作为标准全面兼容性测试
|
|
196
|
-
- 在发布新版本前运行全面测试
|
|
197
|
-
|
|
198
|
-
3. **错误处理**:
|
|
199
|
-
- 对已移除的方法添加更友好的错误提示
|
|
200
|
-
- 考虑在代码中添加方法兼容性检测
|
|
201
|
-
|
|
202
|
-
注:✅ 完全兼容/功能正常 | ⚠️ 功能正常但有注意事项 | ❌ 不兼容/未实现/已移除
|
|
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 {
|
|
@@ -626,9 +633,10 @@ class CacheBase extends EventEmitter {
|
|
|
626
633
|
}
|
|
627
634
|
|
|
628
635
|
/**
|
|
629
|
-
* 获取键的剩余生存时间
|
|
636
|
+
* 获取键的剩余生存时间 - 兼容方法
|
|
630
637
|
* @param {string} key - 键名
|
|
631
638
|
* @returns {Promise<number>} - 返回剩余时间(秒),-1表示永不过期,-2表示键不存在
|
|
639
|
+
* @note 确保与Redis行为完全一致,精确计算剩余时间
|
|
632
640
|
*/
|
|
633
641
|
async ttl(key) {
|
|
634
642
|
try {
|
|
@@ -650,10 +658,10 @@ class CacheBase extends EventEmitter {
|
|
|
650
658
|
}
|
|
651
659
|
return -2;
|
|
652
660
|
} else {
|
|
653
|
-
//
|
|
661
|
+
// 精确计算剩余时间
|
|
654
662
|
const remainingMs = item.expire - Date.now();
|
|
655
|
-
//
|
|
656
|
-
const ttl =
|
|
663
|
+
// 确保返回整数秒,向下取整
|
|
664
|
+
const ttl = Math.floor(remainingMs / 1000);
|
|
657
665
|
return ttl;
|
|
658
666
|
}
|
|
659
667
|
} else {
|
|
@@ -1090,18 +1098,37 @@ class CacheBase extends EventEmitter {
|
|
|
1090
1098
|
}
|
|
1091
1099
|
}
|
|
1092
1100
|
|
|
1101
|
+
/**
|
|
1102
|
+
* 清空缓存 - 兼容方法
|
|
1103
|
+
* @param {string} pattern - 可选的键匹配模式
|
|
1104
|
+
* @returns {Promise<string>} - 返回'OK'
|
|
1105
|
+
* @note 支持模式匹配,与Redis行为一致
|
|
1106
|
+
*/
|
|
1093
1107
|
async clear(pattern) {
|
|
1094
1108
|
try {
|
|
1095
|
-
this.emit('clear_before');
|
|
1109
|
+
this.emit('clear_before', { pattern });
|
|
1096
1110
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
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
|
+
}
|
|
1100
1127
|
|
|
1101
|
-
this.emit('clear_after', { result: 'OK' });
|
|
1128
|
+
this.emit('clear_after', { pattern, result: 'OK' });
|
|
1102
1129
|
return 'OK';
|
|
1103
1130
|
} catch (error) {
|
|
1104
|
-
this.emit('clear_error', { error });
|
|
1131
|
+
this.emit('clear_error', { pattern, error });
|
|
1105
1132
|
$.log.error('[cachebase] clear操作失败:', error);
|
|
1106
1133
|
throw error;
|
|
1107
1134
|
}
|
|
@@ -1146,12 +1173,12 @@ class CacheBase extends EventEmitter {
|
|
|
1146
1173
|
}
|
|
1147
1174
|
|
|
1148
1175
|
/**
|
|
1149
|
-
* 设置列表项 -
|
|
1176
|
+
* 设置列表项 - 兼容Redis LPUSH/RPUSH行为
|
|
1150
1177
|
* @param {string} key - 键名
|
|
1151
1178
|
* @param {any} value - 值(通常应为数组)
|
|
1152
1179
|
* @param {number} maxAge - 过期时间(秒),0表示永不过期
|
|
1153
|
-
* @returns {Promise<
|
|
1154
|
-
* @note
|
|
1180
|
+
* @returns {Promise<number>} - 设置后列表的长度
|
|
1181
|
+
* @note 兼容Redis的列表设置行为,返回列表长度
|
|
1155
1182
|
*/
|
|
1156
1183
|
async list_set(key, value, maxAge = 0) {
|
|
1157
1184
|
try {
|
|
@@ -1171,8 +1198,9 @@ class CacheBase extends EventEmitter {
|
|
|
1171
1198
|
this.list.push(key);
|
|
1172
1199
|
}
|
|
1173
1200
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1201
|
+
const length = arrayValue.length;
|
|
1202
|
+
this.emit('list_set_after', { key, value: arrayValue, maxAge, result: length });
|
|
1203
|
+
return length;
|
|
1176
1204
|
} catch (error) {
|
|
1177
1205
|
this.emit('list_set_error', { key, value, maxAge, error });
|
|
1178
1206
|
$.log.error('[cachebase] list_set操作失败:', error);
|
|
@@ -1181,12 +1209,12 @@ class CacheBase extends EventEmitter {
|
|
|
1181
1209
|
}
|
|
1182
1210
|
|
|
1183
1211
|
/**
|
|
1184
|
-
* 添加列表项 -
|
|
1212
|
+
* 添加列表项 - 兼容Redis LPUSH/RPUSH行为
|
|
1185
1213
|
* @param {string} key - 键名
|
|
1186
1214
|
* @param {any} value - 值
|
|
1187
1215
|
* @param {number} maxAge - 过期时间(秒),0表示永不过期
|
|
1188
|
-
* @returns {Promise<
|
|
1189
|
-
* @note
|
|
1216
|
+
* @returns {Promise<number>} - 添加后列表的长度
|
|
1217
|
+
* @note 兼容Redis的列表追加行为,返回列表长度
|
|
1190
1218
|
*/
|
|
1191
1219
|
async list_add(key, value, maxAge = 0) {
|
|
1192
1220
|
try {
|
|
@@ -1219,8 +1247,9 @@ class CacheBase extends EventEmitter {
|
|
|
1219
1247
|
this.list.push(key);
|
|
1220
1248
|
}
|
|
1221
1249
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1250
|
+
const length = list.length;
|
|
1251
|
+
this.emit('list_add_after', { key, value, maxAge, result: length });
|
|
1252
|
+
return length;
|
|
1224
1253
|
} catch (error) {
|
|
1225
1254
|
this.emit('list_add_error', { key, value, maxAge, error });
|
|
1226
1255
|
$.log.error('[cachebase] list_add操作失败:', error);
|
|
@@ -1229,11 +1258,11 @@ class CacheBase extends EventEmitter {
|
|
|
1229
1258
|
}
|
|
1230
1259
|
|
|
1231
1260
|
/**
|
|
1232
|
-
* 检查列表是否包含指定项 -
|
|
1261
|
+
* 检查列表是否包含指定项 - 兼容Redis SISMEMBER行为
|
|
1233
1262
|
* @param {string} key - 键名
|
|
1234
1263
|
* @param {any} value - 值
|
|
1235
|
-
* @returns {Promise<
|
|
1236
|
-
* @note
|
|
1264
|
+
* @returns {Promise<number>} - 包含返回1,不包含返回0
|
|
1265
|
+
* @note 兼容Redis的SISMEMBER命令,返回数字而非布尔值
|
|
1237
1266
|
*/
|
|
1238
1267
|
async list_has(key, value) {
|
|
1239
1268
|
try {
|
|
@@ -1245,7 +1274,7 @@ class CacheBase extends EventEmitter {
|
|
|
1245
1274
|
const list = Array.isArray(this.data[key].value) ? this.data[key].value : [];
|
|
1246
1275
|
|
|
1247
1276
|
// 对于对象类型的值,使用深度比较
|
|
1248
|
-
let result =
|
|
1277
|
+
let result = 0;
|
|
1249
1278
|
if (typeof value === 'object' && value !== null) {
|
|
1250
1279
|
const valueStr = JSON.stringify(value);
|
|
1251
1280
|
result = list.some(item => {
|
|
@@ -1255,18 +1284,18 @@ class CacheBase extends EventEmitter {
|
|
|
1255
1284
|
// 如果JSON序列化失败,回退到严格相等
|
|
1256
1285
|
return item === value;
|
|
1257
1286
|
}
|
|
1258
|
-
});
|
|
1287
|
+
}) ? 1 : 0;
|
|
1259
1288
|
} else {
|
|
1260
1289
|
// 对于基本类型,使用严格相等
|
|
1261
|
-
result = list.includes(value);
|
|
1290
|
+
result = list.includes(value) ? 1 : 0;
|
|
1262
1291
|
}
|
|
1263
1292
|
|
|
1264
1293
|
this.emit('list_has_after', { key, value, result });
|
|
1265
1294
|
return result;
|
|
1266
1295
|
}
|
|
1267
1296
|
|
|
1268
|
-
this.emit('list_has_after', { key, value, result:
|
|
1269
|
-
return
|
|
1297
|
+
this.emit('list_has_after', { key, value, result: 0 });
|
|
1298
|
+
return 0;
|
|
1270
1299
|
} catch (error) {
|
|
1271
1300
|
this.emit('list_has_error', { key, value, error });
|
|
1272
1301
|
$.log.error('[cachebase] list_has操作失败:', error);
|
|
@@ -1275,28 +1304,41 @@ class CacheBase extends EventEmitter {
|
|
|
1275
1304
|
}
|
|
1276
1305
|
|
|
1277
1306
|
/**
|
|
1278
|
-
* 获取列表 -
|
|
1307
|
+
* 获取列表 - 兼容Redis LRANGE行为
|
|
1279
1308
|
* @param {string} key - 键名
|
|
1309
|
+
* @param {number} start - 可选的起始索引,默认为0
|
|
1310
|
+
* @param {number} stop - 可选的结束索引,默认为-1(全部)
|
|
1280
1311
|
* @returns {Promise<Array>} - 列表数据,确保始终返回数组类型
|
|
1281
|
-
* @note
|
|
1312
|
+
* @note 兼容Redis的LRANGE命令,支持范围获取
|
|
1282
1313
|
*/
|
|
1283
|
-
async list_get(key) {
|
|
1314
|
+
async list_get(key, start = 0, stop = -1) {
|
|
1284
1315
|
try {
|
|
1285
|
-
this.emit('list_get_before', { key });
|
|
1316
|
+
this.emit('list_get_before', { key, start, stop });
|
|
1286
1317
|
|
|
1287
1318
|
// 检查键是否存在且未过期
|
|
1288
1319
|
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
1289
1320
|
// 确保返回数组类型,如果不是数组则转换为空数组
|
|
1290
|
-
const
|
|
1291
|
-
|
|
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 });
|
|
1292
1334
|
return result;
|
|
1293
1335
|
}
|
|
1294
1336
|
|
|
1295
1337
|
// 键不存在或已过期时返回空数组
|
|
1296
|
-
this.emit('list_get_after', { key, result: [] });
|
|
1338
|
+
this.emit('list_get_after', { key, start, stop, result: [] });
|
|
1297
1339
|
return [];
|
|
1298
1340
|
} catch (error) {
|
|
1299
|
-
this.emit('list_get_error', { key, error });
|
|
1341
|
+
this.emit('list_get_error', { key, start, stop, error });
|
|
1300
1342
|
$.log.error('[cachebase] list_get操作失败:', error);
|
|
1301
1343
|
throw error;
|
|
1302
1344
|
}
|
|
@@ -1357,6 +1399,49 @@ class CacheBase extends EventEmitter {
|
|
|
1357
1399
|
}
|
|
1358
1400
|
}
|
|
1359
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
|
+
|
|
1360
1445
|
/**
|
|
1361
1446
|
* 增加浮点数(兼容方法)
|
|
1362
1447
|
* @param {string} key - 键名
|
package/package.json
CHANGED
|
@@ -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();
|