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.
@@ -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
- | list_set | ✅ | ⚠️ | ⚠️ | ⚠️ | 所有方式均通过通用实现支持,但底层可能需要各自实现 |
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 | ⚠️ | ⚠️ | ⚠️ | ⚠️ | 所有方式均返回0,但实际能删除字段 |
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
- | exists | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
44
- | mget | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作,返回正确的结果数组 |
45
- | mset | ✅ | ✅ | ✅ | ✅ | 所有方式均正常工作 |
46
- | pexpire | ✅ | ✅ | ✅ | ✅ | 毫秒级过期时间设置,所有方式均正常工作 |
47
- | persist | ✅ | ✅ | ✅ | ✅ | 移除过期时间,所有方式均正常工作 |
48
- | strlen | ✅ | ✅ | ✅ | ✅ | 字符串长度获取,所有方式均正常工作 |
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
- | 哈希表基本操作 | ⚠️ | ⚠️ | ⚠️ | ⚠️ | hdel方法返回0,但实际能删除字段,其他方法正常 |
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
- - **总测试用例**:43个
93
- - **通过数**:43个测试用例
94
- - **整体成功率**:100%
95
- - **注意事项**:hdel方法在所有缓存方式下返回0,但实际能删除字段
96
-
97
- ### 所有缓存方式都支持的功能:
98
- - **核心键值操作**:set, get, exists, del, has, keys, sort(add除外)
99
- - **哈希表操作**:hset, hget, hgetall, hdel, hmset, hmget, hlen
100
- - **过期时间操作**:expire, ttl, persist, pexpire
101
- - **原子递增操作**:incr, decr
102
- - **批量操作**:mset, mget
103
- - **集合操作**:sadd, srem, sismember, smembers
104
- - **字符串操作**:strlen
105
- - **类型检测**:type
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
- delete this.data[key];
338
- const index = this.list.indexOf(key);
339
- if (index !== -1) {
340
- this.list.splice(index, 1);
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
- // 计算剩余时间,增加容错性处理接近0但应该为正的情况
661
+ // 精确计算剩余时间
654
662
  const remainingMs = item.expire - Date.now();
655
- // 即使剩余时间非常小(但仍为正),也返回至少1秒,避免测试失败
656
- const ttl = remainingMs > 0 ? Math.max(1, Math.floor(remainingMs / 1000)) : 1;
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
- this.data = {};
1099
- this.list = [];
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<boolean>} - 是否成功
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
- this.emit('list_set_after', { key, value: arrayValue, maxAge, result: true });
1175
- return true;
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<boolean>} - 是否成功
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
- this.emit('list_add_after', { key, value, maxAge, result: true });
1223
- return true;
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<boolean>} - 是否包含
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 = false;
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: false });
1269
- return false;
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 result = Array.isArray(this.data[key].value) ? [...this.data[key].value] : [];
1291
- this.emit('list_get_after', { key, result });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_cachebase",
3
- "version": "1.8.4",
3
+ "version": "1.8.5",
4
4
  "description": "一个轻量级的本地缓存类库,提供与Redis兼容的API接口,支持过期时间设置、哈希表操作、数值操作、字符串操作等功能,以及完整的事件通知系统和多文件持久化功能。",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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();