monsqlize 1.0.0

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +2474 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1368 -0
  4. package/index.d.ts +1052 -0
  5. package/lib/cache.js +491 -0
  6. package/lib/common/cursor.js +58 -0
  7. package/lib/common/docs-urls.js +72 -0
  8. package/lib/common/index-options.js +222 -0
  9. package/lib/common/log.js +60 -0
  10. package/lib/common/namespace.js +21 -0
  11. package/lib/common/normalize.js +33 -0
  12. package/lib/common/page-result.js +42 -0
  13. package/lib/common/runner.js +56 -0
  14. package/lib/common/server-features.js +231 -0
  15. package/lib/common/shape-builders.js +26 -0
  16. package/lib/common/validation.js +49 -0
  17. package/lib/connect.js +76 -0
  18. package/lib/constants.js +54 -0
  19. package/lib/count-queue.js +187 -0
  20. package/lib/distributed-cache-invalidator.js +259 -0
  21. package/lib/errors.js +157 -0
  22. package/lib/index.js +352 -0
  23. package/lib/logger.js +224 -0
  24. package/lib/model/examples/test.js +114 -0
  25. package/lib/mongodb/common/accessor-helpers.js +44 -0
  26. package/lib/mongodb/common/agg-pipeline.js +32 -0
  27. package/lib/mongodb/common/iid.js +27 -0
  28. package/lib/mongodb/common/lexicographic-expr.js +52 -0
  29. package/lib/mongodb/common/shape.js +31 -0
  30. package/lib/mongodb/common/sort.js +38 -0
  31. package/lib/mongodb/common/transaction-aware.js +24 -0
  32. package/lib/mongodb/connect.js +178 -0
  33. package/lib/mongodb/index.js +458 -0
  34. package/lib/mongodb/management/admin-ops.js +199 -0
  35. package/lib/mongodb/management/bookmark-ops.js +166 -0
  36. package/lib/mongodb/management/cache-ops.js +49 -0
  37. package/lib/mongodb/management/collection-ops.js +386 -0
  38. package/lib/mongodb/management/database-ops.js +201 -0
  39. package/lib/mongodb/management/index-ops.js +474 -0
  40. package/lib/mongodb/management/index.js +16 -0
  41. package/lib/mongodb/management/namespace.js +30 -0
  42. package/lib/mongodb/management/validation-ops.js +267 -0
  43. package/lib/mongodb/queries/aggregate.js +133 -0
  44. package/lib/mongodb/queries/chain.js +623 -0
  45. package/lib/mongodb/queries/count.js +88 -0
  46. package/lib/mongodb/queries/distinct.js +68 -0
  47. package/lib/mongodb/queries/find-and-count.js +183 -0
  48. package/lib/mongodb/queries/find-by-ids.js +235 -0
  49. package/lib/mongodb/queries/find-one-by-id.js +170 -0
  50. package/lib/mongodb/queries/find-one.js +61 -0
  51. package/lib/mongodb/queries/find-page.js +565 -0
  52. package/lib/mongodb/queries/find.js +161 -0
  53. package/lib/mongodb/queries/index.js +49 -0
  54. package/lib/mongodb/writes/delete-many.js +181 -0
  55. package/lib/mongodb/writes/delete-one.js +173 -0
  56. package/lib/mongodb/writes/find-one-and-delete.js +193 -0
  57. package/lib/mongodb/writes/find-one-and-replace.js +222 -0
  58. package/lib/mongodb/writes/find-one-and-update.js +223 -0
  59. package/lib/mongodb/writes/increment-one.js +243 -0
  60. package/lib/mongodb/writes/index.js +41 -0
  61. package/lib/mongodb/writes/insert-batch.js +498 -0
  62. package/lib/mongodb/writes/insert-many.js +218 -0
  63. package/lib/mongodb/writes/insert-one.js +171 -0
  64. package/lib/mongodb/writes/replace-one.js +199 -0
  65. package/lib/mongodb/writes/result-handler.js +236 -0
  66. package/lib/mongodb/writes/update-many.js +205 -0
  67. package/lib/mongodb/writes/update-one.js +207 -0
  68. package/lib/mongodb/writes/upsert-one.js +190 -0
  69. package/lib/multi-level-cache.js +189 -0
  70. package/lib/operators.js +330 -0
  71. package/lib/redis-cache-adapter.js +237 -0
  72. package/lib/transaction/CacheLockManager.js +161 -0
  73. package/lib/transaction/DistributedCacheLockManager.js +239 -0
  74. package/lib/transaction/Transaction.js +314 -0
  75. package/lib/transaction/TransactionManager.js +266 -0
  76. package/lib/transaction/index.js +10 -0
  77. package/package.json +111 -0
@@ -0,0 +1,330 @@
1
+ module.exports = {
2
+
3
+ // 比较运算符(查询阶段)
4
+ comparisonOperators:{
5
+ '$eq': { mysql: '=' }, // 等于 (MongoDB: $eq) —— null 在实现层转为 IS NULL
6
+ '$ne': { mysql: '<>' }, // 不等于 (MongoDB: $ne) —— null 在实现层转为 IS NOT NULL
7
+ '$gt': { mysql: '>' }, // 大于 (MongoDB: $gt)
8
+ '$gte': { mysql: '>=' }, // 大于等于 (MongoDB: $gte)
9
+ '$lt': { mysql: '<' }, // 小于 (MongoDB: $lt)
10
+ '$lte': { mysql: '<=' }, // 小于等于 (MongoDB: $lte)
11
+ '$in': { mysql: 'IN' }, // 在列表中 (MongoDB: $in)
12
+ '$nin': { mysql: 'NOT IN' }, // 不在列表中 (MongoDB: $nin)
13
+ },
14
+
15
+ // 逻辑运算符(查询阶段)
16
+ logicalOperators:{
17
+ '$and': { mysql: 'AND' }, // 逻辑与 (MongoDB: $and)
18
+ '$or': { mysql: 'OR' }, // 逻辑或 (MongoDB: $or)
19
+ '$not': { mysql: 'NOT' }, // 逻辑非 (MongoDB: $not) —— 使用 NOT ( ... ) 包裹字段条件
20
+ '$nor': { mysql: '' } // 逻辑或非 (MongoDB: $nor) —— 实现为 NOT ( ... OR ... ) 包裹(无独立 SQL 运算符)
21
+ },
22
+
23
+ // 元素运算符(查询阶段)
24
+ elementOperators:{
25
+ '$exists': { mysql: 'IS [NOT] NULL' }, // 是否存在 (MongoDB: $exists) —— MySQL 映射为 IS [NOT] NULL(列存在性以 NULL 判定)
26
+ '$type': { mysql: '' } // 类型 (MongoDB: $type) —— 未实现
27
+ },
28
+
29
+ // 评估运算符(查询阶段)
30
+ evaluationOperators:{
31
+ '$expr': { mysql: '' }, // 使用聚合表达式 —— MySQL 端不支持
32
+ '$jsonSchema': { mysql: '' }, // JSON Schema —— 未实现
33
+ '$mod': { mysql: 'col % d = r' }, // 模运算 —— MySQL 使用取模:col % divisor = remainder(参数化)
34
+ '$regex': { mysql: 'REGEXP' }, // 正则(MySQL: REGEXP)
35
+ '$text': { mysql: 'MATCH...AGAINST' }, // 全文搜索 —— 使用 MATCH(...) AGAINST (? [MODE]),需指定 $columns
36
+ '$where': { mysql: '' } // JavaScript 表达式 —— MySQL 端不支持
37
+ },
38
+
39
+ // 数组运算符(查询阶段)
40
+ arrayOperators:{
41
+ '$all': { mysql: '' }, // 未实现
42
+ '$elemMatch': { mysql: '' }, // 未实现
43
+ '$size': { mysql: '' }, // 未实现
44
+ },
45
+
46
+ // 位运算符(查询阶段)
47
+ bitOperators:{
48
+ '$bitsAllClear': { mysql: '' }, // 未实现
49
+ '$bitsAllSet': { mysql: '' }, // 未实现
50
+ '$bitsAnyClear': { mysql: '' }, // 未实现
51
+ '$bitsAnySet': { mysql: '' }, // 未实现
52
+ },
53
+
54
+ // 地理空间运算符(查询阶段)
55
+ geospatialOperators:{
56
+ '$geoIntersects': { mysql: '' }, // 未实现
57
+ '$geoWithin': { mysql: '' }, // 未实现
58
+ '$near': { mysql: '' }, // 未实现
59
+ '$nearSphere': { mysql: '' } // 未实现
60
+ },
61
+
62
+ // 投影运算符(读取阶段,当前由适配器自行处理语义)
63
+ projectionOperators:{
64
+ '$': { mysql: '' }, // 未实现
65
+ '$elemMatch':{ mysql: '' }, // 未实现
66
+ '$meta': { mysql: '' }, // 未实现
67
+ '$slice': { mysql: '' } // 未实现
68
+ },
69
+
70
+ // 更新运算符(当前不在本项目范围,预留映射位)
71
+ updateOperators:{
72
+ // 字段更新运算符
73
+ fieldUpdateOperators:{
74
+ '$currentDate': { mysql: '' },
75
+ '$inc': { mysql: '' },
76
+ '$min': { mysql: '' },
77
+ '$max': { mysql: '' },
78
+ '$mul': { mysql: '' },
79
+ '$rename': { mysql: '' },
80
+ '$set': { mysql: '' },
81
+ '$setOnInsert': { mysql: '' },
82
+ '$unset': { mysql: '' },
83
+ },
84
+
85
+ // 数组更新运算符
86
+ arrayUpdateOperators:{
87
+ '$addToSet': { mysql: '' },
88
+ '$pop': { mysql: '' },
89
+ '$pull': { mysql: '' },
90
+ '$push': { mysql: '' },
91
+ '$pullAll': { mysql: '' },
92
+ },
93
+
94
+ // 数组更新修饰符
95
+ arrayUpdateModifiers:{
96
+ '$each': { mysql: '' },
97
+ '$position':{ mysql: '' },
98
+ '$slice': { mysql: '' },
99
+ '$sort': { mysql: '' }
100
+ },
101
+
102
+ // 按位更新运算符
103
+ bitUpdateOperators:{
104
+ '$bit': { mysql: '' }
105
+ }
106
+ },
107
+
108
+ // 聚合管道阶段(预留)
109
+ aggregationPipelineStages:{
110
+ '$addFields': { mysql: '' },
111
+ '$bucket': { mysql: '' },
112
+ '$bucketAuto': { mysql: '' },
113
+ '$collStats': { mysql: '' },
114
+ '$count': { mysql: '' },
115
+ '$facet': { mysql: '' },
116
+ '$geoNear': { mysql: '' },
117
+ '$graphLookup': { mysql: '' },
118
+ '$group': { mysql: '' },
119
+ '$indexStats': { mysql: '' },
120
+ '$limit': { mysql: '' },
121
+ '$lookup': { mysql: '' },
122
+ '$match': { mysql: '' },
123
+ '$merge': { mysql: '' },
124
+ '$out': { mysql: '' },
125
+ '$project': { mysql: '' },
126
+ '$redact': { mysql: '' },
127
+ '$replaceRoot': { mysql: '' },
128
+ '$replaceWith': { mysql: '' },
129
+ '$sample': { mysql: '' },
130
+ '$set': { mysql: '' },
131
+ '$skip': { mysql: '' },
132
+ '$sort': { mysql: '' },
133
+ '$sortByCount': { mysql: '' },
134
+ '$unionWith': { mysql: '' },
135
+ '$unset': { mysql: '' },
136
+ '$unwind': { mysql: '' }
137
+ },
138
+
139
+ // 聚合表达式运算符(预留)
140
+ aggregationExpressionOperators:{
141
+
142
+ // 算术运算符
143
+ arithmeticOperators:{
144
+ '$abs': { mysql: '' },
145
+ '$add': { mysql: '' },
146
+ '$ceil': { mysql: '' },
147
+ '$divide': { mysql: '' },
148
+ '$exp': { mysql: '' },
149
+ '$floor': { mysql: '' },
150
+ '$ln': { mysql: '' },
151
+ '$log': { mysql: '' },
152
+ '$log10': { mysql: '' },
153
+ '$mod': { mysql: '' },
154
+ '$multiply': { mysql: '' },
155
+ '$pow': { mysql: '' },
156
+ '$round': { mysql: '' },
157
+ '$sqrt': { mysql: '' },
158
+ '$subtract': { mysql: '' },
159
+ '$trunc': { mysql: '' }
160
+ },
161
+
162
+ // 数组运算符
163
+ arrayOperators:{
164
+ '$arrayElemAt': { mysql: '' },
165
+ '$arrayToObject': { mysql: '' },
166
+ '$concatArrays': { mysql: '' },
167
+ '$filter': { mysql: '' },
168
+ '$first': { mysql: '' },
169
+ '$in': { mysql: '' },
170
+ '$indexOfArray': { mysql: '' },
171
+ '$isArray': { mysql: '' },
172
+ '$last': { mysql: '' },
173
+ '$map': { mysql: '' },
174
+ '$objectToArray': { mysql: '' },
175
+ '$range': { mysql: '' },
176
+ '$reduce': { mysql: '' },
177
+ '$reverseArray': { mysql: '' },
178
+ '$size': { mysql: '' },
179
+ '$slice': { mysql: '' },
180
+ '$zip': { mysql: '' }
181
+ },
182
+
183
+ // 布尔运算符
184
+ booleanOperators:{
185
+ '$and': { mysql: '' },
186
+ '$not': { mysql: '' },
187
+ '$or': { mysql: '' }
188
+ },
189
+
190
+ // 比较运算符
191
+ comparisonOperators:{
192
+ '$cmp': { mysql: '' },
193
+ '$eq': { mysql: '' },
194
+ '$gt': { mysql: '' },
195
+ '$gte': { mysql: '' },
196
+ '$lt': { mysql: '' },
197
+ '$lte': { mysql: '' },
198
+ '$ne': { mysql: '' }
199
+ },
200
+
201
+ // 条件运算符
202
+ conditionalOperators:{
203
+ '$cond': { mysql: '' },
204
+ '$ifNull': { mysql: '' },
205
+ '$switch': { mysql: '' }
206
+ },
207
+
208
+ // 数据类型运算符
209
+ dataTypeOperators:{
210
+ '$type': { mysql: '' },
211
+ '$convert': { mysql: '' },
212
+ '$toBool': { mysql: '' },
213
+ '$toDate': { mysql: '' },
214
+ '$toDecimal': { mysql: '' },
215
+ '$toDouble': { mysql: '' },
216
+ '$toInt': { mysql: '' },
217
+ '$toLong': { mysql: '' },
218
+ '$toObjectId': { mysql: '' },
219
+ '$toString': { mysql: '' }
220
+ },
221
+
222
+ // 日期运算符
223
+ dateOperators:{
224
+ '$dateAdd': { mysql: '' },
225
+ '$dateDiff': { mysql: '' },
226
+ '$dateFromParts': { mysql: '' },
227
+ '$dateFromString':{ mysql: '' },
228
+ '$dateSubtract': { mysql: '' },
229
+ '$dateToParts': { mysql: '' },
230
+ '$dateToString': { mysql: '' },
231
+ '$dayOfMonth': { mysql: '' },
232
+ '$dayOfWeek': { mysql: '' },
233
+ '$dayOfYear': { mysql: '' },
234
+ '$hour': { mysql: '' },
235
+ '$isoDayOfWeek': { mysql: '' },
236
+ '$isoWeek': { mysql: '' },
237
+ '$isoWeekYear': { mysql: '' },
238
+ '$millisecond': { mysql: '' },
239
+ '$minute': { mysql: '' },
240
+ '$month': { mysql: '' },
241
+ '$second': { mysql: '' },
242
+ '$week': { mysql: '' },
243
+ '$year': { mysql: '' }
244
+ },
245
+
246
+ // 字符串运算符
247
+ stringOperators:{
248
+ '$concat': { mysql: '' },
249
+ '$indexOfBytes': { mysql: '' },
250
+ '$indexOfCP': { mysql: '' },
251
+ '$ltrim': { mysql: '' },
252
+ '$regexFind': { mysql: '' },
253
+ '$regexFindAll': { mysql: '' },
254
+ '$regexMatch': { mysql: '' },
255
+ '$replaceAll': { mysql: '' },
256
+ '$replaceOne': { mysql: '' },
257
+ '$rtrim': { mysql: '' },
258
+ '$split': { mysql: '' },
259
+ '$strcasecmp': { mysql: '' },
260
+ '$strLenBytes': { mysql: '' },
261
+ '$strLenCP': { mysql: '' },
262
+ '$substr': { mysql: '' },
263
+ '$substrBytes': { mysql: '' },
264
+ '$substrCP': { mysql: '' },
265
+ '$toLower': { mysql: '' },
266
+ '$toUpper': { mysql: '' },
267
+ '$trim': { mysql: '' }
268
+ },
269
+
270
+ // 文本运算符
271
+ textOperators:{
272
+ '$meta': { mysql: '' }
273
+ },
274
+
275
+ // 变量运算符
276
+ variableOperators:{
277
+ '$$NOW': { mysql: '' },
278
+ '$$ROOT': { mysql: '' },
279
+ '$$CURRENT': { mysql: '' },
280
+ '$$DESCEND': { mysql: '' },
281
+ '$$PRUNE': { mysql: '' },
282
+ '$$KEEP': { mysql: '' }
283
+ },
284
+
285
+ // 累加器运算符(group 阶段)
286
+ accumulatorOperatorsGroup:{
287
+ '$accumulator': { mysql: '' },
288
+ '$addToSet': { mysql: '' },
289
+ '$avg': { mysql: '' },
290
+ '$count': { mysql: '' },
291
+ '$first': { mysql: '' },
292
+ '$last': { mysql: '' },
293
+ '$max': { mysql: '' },
294
+ '$mergeObjects': { mysql: '' },
295
+ '$min': { mysql: '' },
296
+ '$push': { mysql: '' },
297
+ '$stdDevPop': { mysql: '' },
298
+ '$stdDevSamp': { mysql: '' },
299
+ '$sum': { mysql: '' }
300
+ },
301
+
302
+ // 累加器运算符(project 阶段)
303
+ accumulatorOperatorsProject:{
304
+ '$avg': { mysql: '' },
305
+ '$max': { mysql: '' },
306
+ '$min': { mysql: '' },
307
+ '$stdDevPop': { mysql: '' },
308
+ '$stdDevSamp': { mysql: '' },
309
+ '$sum': { mysql: '' }
310
+ }
311
+ },
312
+
313
+ // 游标方法(仅保留占位,非 SQL 语义)
314
+ cursorMethods:{
315
+ '$addCursorFlag': { mysql: '' },
316
+ '$batchSize': { mysql: '' },
317
+ '$close': { mysql: '' },
318
+ '$comment': { mysql: '' },
319
+ '$itcount': { mysql: '' },
320
+ '$isExhaust': { mysql: '' },
321
+ '$isDead': { mysql: '' },
322
+ '$isAlive': { mysql: '' },
323
+ '$maxTimeMS': { mysql: '' },
324
+ '$readConcern': { mysql: '' },
325
+ '$readPref': { mysql: '' },
326
+ '$setBatchSize': { mysql: '' },
327
+ '$setReadConcern': { mysql: '' },
328
+ '$setReadPref': { mysql: '' }
329
+ }
330
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Redis 缓存适配器:将 Redis 封装为 CacheLike 接口
3
+ * 支持直接传入 Redis URL 字符串或 ioredis 实例
4
+ *
5
+ * @example
6
+ * const { createRedisCacheAdapter } = require('monsqlize/lib/redis-cache-adapter');
7
+ *
8
+ * // 方式 1:传入 URL 字符串(推荐)
9
+ * const cache = createRedisCacheAdapter('redis://localhost:6379/0');
10
+ *
11
+ * // 方式 2:传入 ioredis 实例
12
+ * const Redis = require('ioredis');
13
+ * const redis = new Redis('redis://localhost:6379/0');
14
+ * const cache = createRedisCacheAdapter(redis);
15
+ */
16
+
17
+ /**
18
+ * 创建 Redis 缓存适配器
19
+ * @param {string|Object} redisUrlOrInstance - Redis URL 字符串或 ioredis 实例
20
+ * @returns {Object} 实现了 CacheLike 接口的缓存对象
21
+ */
22
+ function createRedisCacheAdapter(redisUrlOrInstance) {
23
+ let redis;
24
+ let shouldCloseOnDestroy = false;
25
+
26
+ // 如果传入的是字符串,自动创建 Redis 实例
27
+ if (typeof redisUrlOrInstance === 'string') {
28
+ try {
29
+ const IORedis = require('ioredis');
30
+ redis = new IORedis(redisUrlOrInstance);
31
+ shouldCloseOnDestroy = true;
32
+ } catch (error) {
33
+ throw new Error(
34
+ 'ioredis 未安装。请运行: npm install ioredis\n' +
35
+ '或传入已创建的 ioredis 实例'
36
+ );
37
+ }
38
+ } else if (redisUrlOrInstance && typeof redisUrlOrInstance === 'object') {
39
+ // 传入的是 ioredis 实例
40
+ redis = redisUrlOrInstance;
41
+ shouldCloseOnDestroy = false;
42
+ } else {
43
+ throw new Error('redisUrlOrInstance 必须是 Redis URL 字符串或 ioredis 实例');
44
+ }
45
+
46
+ // 实现 CacheLike 接口的 10 个方法
47
+ return {
48
+ /**
49
+ * 获取单个缓存值
50
+ * @param {string} key
51
+ * @returns {Promise<any>}
52
+ */
53
+ async get(key) {
54
+ try {
55
+ const val = await redis.get(key);
56
+ return val ? JSON.parse(val) : undefined;
57
+ } catch (error) {
58
+ // 解析失败返回 undefined
59
+ return undefined;
60
+ }
61
+ },
62
+
63
+ /**
64
+ * 设置单个缓存值
65
+ * @param {string} key
66
+ * @param {any} val
67
+ * @param {number} ttl - TTL(毫秒)
68
+ * @returns {Promise<void>}
69
+ */
70
+ async set(key, val, ttl = 0) {
71
+ const str = JSON.stringify(val);
72
+ if (ttl > 0) {
73
+ await redis.psetex(key, ttl, str);
74
+ } else {
75
+ await redis.set(key, str);
76
+ }
77
+ },
78
+
79
+ /**
80
+ * 删除单个缓存项
81
+ * @param {string} key
82
+ * @returns {Promise<boolean>}
83
+ */
84
+ async del(key) {
85
+ const result = await redis.del(key);
86
+ return result > 0;
87
+ },
88
+
89
+ /**
90
+ * 检查键是否存在
91
+ * @param {string} key
92
+ * @returns {Promise<boolean>}
93
+ */
94
+ async exists(key) {
95
+ const result = await redis.exists(key);
96
+ return result > 0;
97
+ },
98
+
99
+ /**
100
+ * 批量获取
101
+ * @param {string[]} keys
102
+ * @returns {Promise<Object>}
103
+ */
104
+ async getMany(keys) {
105
+ if (!keys || keys.length === 0) return {};
106
+
107
+ const values = await redis.mget(keys);
108
+ const result = {};
109
+
110
+ keys.forEach((key, i) => {
111
+ if (values[i]) {
112
+ try {
113
+ result[key] = JSON.parse(values[i]);
114
+ } catch {
115
+ // 解析失败跳过
116
+ }
117
+ }
118
+ });
119
+
120
+ return result;
121
+ },
122
+
123
+ /**
124
+ * 批量设置
125
+ * @param {Object} obj - 键值对对象
126
+ * @param {number} ttl - TTL(毫秒)
127
+ * @returns {Promise<boolean>}
128
+ */
129
+ async setMany(obj, ttl = 0) {
130
+ if (!obj || Object.keys(obj).length === 0) return true;
131
+
132
+ const pipeline = redis.pipeline();
133
+
134
+ for (const [key, val] of Object.entries(obj)) {
135
+ const str = JSON.stringify(val);
136
+ if (ttl > 0) {
137
+ pipeline.psetex(key, ttl, str);
138
+ } else {
139
+ pipeline.set(key, str);
140
+ }
141
+ }
142
+
143
+ await pipeline.exec();
144
+ return true;
145
+ },
146
+
147
+ /**
148
+ * 批量删除
149
+ * @param {string[]} keys
150
+ * @returns {Promise<number>}
151
+ */
152
+ async delMany(keys) {
153
+ if (!keys || keys.length === 0) return 0;
154
+ return await redis.del(...keys);
155
+ },
156
+
157
+ /**
158
+ * 按模式删除(支持通配符 *)
159
+ * @param {string} pattern
160
+ * @returns {Promise<number>}
161
+ */
162
+ async delPattern(pattern) {
163
+ // 使用 SCAN 避免阻塞(生产环境推荐)
164
+ let cursor = '0';
165
+ let deletedCount = 0;
166
+
167
+ do {
168
+ const [nextCursor, keys] = await redis.scan(
169
+ cursor,
170
+ 'MATCH', pattern,
171
+ 'COUNT', 100
172
+ );
173
+ cursor = nextCursor;
174
+
175
+ if (keys.length > 0) {
176
+ deletedCount += await redis.del(...keys);
177
+ }
178
+ } while (cursor !== '0');
179
+
180
+ return deletedCount;
181
+ },
182
+
183
+ /**
184
+ * 清空所有缓存(谨慎使用)
185
+ * @returns {Promise<void>}
186
+ */
187
+ async clear() {
188
+ await redis.flushdb();
189
+ },
190
+
191
+ /**
192
+ * 获取所有键(可选模式匹配)
193
+ * @param {string} pattern
194
+ * @returns {Promise<string[]>}
195
+ */
196
+ async keys(pattern = '*') {
197
+ // 使用 SCAN 避免阻塞
198
+ const allKeys = [];
199
+ let cursor = '0';
200
+
201
+ do {
202
+ const [nextCursor, keys] = await redis.scan(
203
+ cursor,
204
+ 'MATCH', pattern,
205
+ 'COUNT', 100
206
+ );
207
+ cursor = nextCursor;
208
+ allKeys.push(...keys);
209
+ } while (cursor !== '0');
210
+
211
+ return allKeys;
212
+ },
213
+
214
+ /**
215
+ * 关闭 Redis 连接(仅当自动创建时才会关闭)
216
+ * @returns {Promise<void>}
217
+ */
218
+ async close() {
219
+ if (shouldCloseOnDestroy && redis) {
220
+ try {
221
+ await redis.quit();
222
+ } catch {
223
+ // 忽略关闭错误
224
+ }
225
+ }
226
+ },
227
+
228
+ /**
229
+ * 获取底层 Redis 实例(用于高级操作)
230
+ */
231
+ getRedisInstance() {
232
+ return redis;
233
+ }
234
+ };
235
+ }
236
+
237
+ module.exports = { createRedisCacheAdapter };