monsqlize 1.3.0 → 2.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 (172) hide show
  1. package/CHANGELOG.md +56 -60
  2. package/LICENSE +201 -21
  3. package/README.md +537 -1828
  4. package/changelogs/README.md +160 -0
  5. package/changelogs/v2.0.0.md +222 -0
  6. package/dist/cjs/index.cjs +10600 -0
  7. package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
  8. package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
  9. package/dist/cjs/transaction/Transaction.cjs +158 -0
  10. package/dist/cjs/transaction/TransactionManager.cjs +298 -0
  11. package/dist/esm/index.mjs +10650 -0
  12. package/dist/types/base.d.ts +81 -0
  13. package/dist/types/collection.d.ts +1031 -0
  14. package/dist/types/expression.d.ts +115 -0
  15. package/dist/types/index.d.ts +23 -0
  16. package/dist/types/lock.d.ts +74 -0
  17. package/dist/types/model.d.ts +526 -0
  18. package/dist/types/mongodb.d.ts +49 -0
  19. package/dist/types/monsqlize.d.ts +491 -0
  20. package/dist/types/pool.d.ts +84 -0
  21. package/dist/types/runtime.d.ts +362 -0
  22. package/dist/types/saga.d.ts +143 -0
  23. package/dist/types/slow-query-log.d.ts +126 -0
  24. package/dist/types/sync.d.ts +103 -0
  25. package/dist/types/transaction.d.ts +132 -0
  26. package/package.json +67 -69
  27. package/index.d.ts +0 -206
  28. package/index.mjs +0 -52
  29. package/lib/cache-invalidation.js +0 -279
  30. package/lib/cache.js +0 -530
  31. package/lib/common/cursor.js +0 -59
  32. package/lib/common/docs-urls.js +0 -73
  33. package/lib/common/index-options.js +0 -223
  34. package/lib/common/log.js +0 -61
  35. package/lib/common/namespace.js +0 -22
  36. package/lib/common/normalize.js +0 -34
  37. package/lib/common/page-result.js +0 -43
  38. package/lib/common/runner.js +0 -57
  39. package/lib/common/server-features.js +0 -232
  40. package/lib/common/shape-builders.js +0 -27
  41. package/lib/common/validation.js +0 -113
  42. package/lib/connect.js +0 -99
  43. package/lib/constants.js +0 -55
  44. package/lib/count-queue.js +0 -188
  45. package/lib/distributed-cache-invalidator.js +0 -260
  46. package/lib/errors.js +0 -168
  47. package/lib/expression/cache/ExpressionCache.js +0 -114
  48. package/lib/expression/compiler/ExpressionCompiler.js +0 -1090
  49. package/lib/expression/compiler/ExpressionCompilerExtensions.js +0 -531
  50. package/lib/expression/detector.js +0 -84
  51. package/lib/expression/factory.js +0 -29
  52. package/lib/expression/index.js +0 -19
  53. package/lib/function-cache.js +0 -533
  54. package/lib/index.js +0 -1251
  55. package/lib/infrastructure/ConnectionPoolManager.js +0 -464
  56. package/lib/infrastructure/HealthChecker.js +0 -281
  57. package/lib/infrastructure/PoolConfig.js +0 -199
  58. package/lib/infrastructure/PoolSelector.js +0 -225
  59. package/lib/infrastructure/PoolStats.js +0 -244
  60. package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -212
  61. package/lib/infrastructure/ssh-tunnel.js +0 -41
  62. package/lib/infrastructure/uri-parser.js +0 -36
  63. package/lib/lock/Lock.js +0 -67
  64. package/lib/lock/errors.js +0 -28
  65. package/lib/lock/index.js +0 -13
  66. package/lib/logger.js +0 -225
  67. package/lib/model/examples/test.js +0 -311
  68. package/lib/model/features/defaults.js +0 -161
  69. package/lib/model/features/populate.js +0 -568
  70. package/lib/model/features/relations.js +0 -120
  71. package/lib/model/features/soft-delete.js +0 -349
  72. package/lib/model/features/version.js +0 -157
  73. package/lib/model/features/virtuals.js +0 -219
  74. package/lib/model/index.js +0 -1265
  75. package/lib/mongodb/common/accessor-helpers.js +0 -59
  76. package/lib/mongodb/common/agg-pipeline.js +0 -36
  77. package/lib/mongodb/common/aggregation-validator.js +0 -127
  78. package/lib/mongodb/common/iid.js +0 -28
  79. package/lib/mongodb/common/lexicographic-expr.js +0 -53
  80. package/lib/mongodb/common/shape.js +0 -32
  81. package/lib/mongodb/common/sort.js +0 -39
  82. package/lib/mongodb/common/transaction-aware.js +0 -25
  83. package/lib/mongodb/connect.js +0 -234
  84. package/lib/mongodb/index.js +0 -639
  85. package/lib/mongodb/management/admin-ops.js +0 -200
  86. package/lib/mongodb/management/bookmark-ops.js +0 -167
  87. package/lib/mongodb/management/cache-ops.js +0 -50
  88. package/lib/mongodb/management/collection-ops.js +0 -387
  89. package/lib/mongodb/management/database-ops.js +0 -202
  90. package/lib/mongodb/management/index-ops.js +0 -475
  91. package/lib/mongodb/management/index.js +0 -17
  92. package/lib/mongodb/management/namespace.js +0 -31
  93. package/lib/mongodb/management/validation-ops.js +0 -268
  94. package/lib/mongodb/queries/aggregate.js +0 -172
  95. package/lib/mongodb/queries/chain.js +0 -631
  96. package/lib/mongodb/queries/count.js +0 -99
  97. package/lib/mongodb/queries/distinct.js +0 -78
  98. package/lib/mongodb/queries/find-and-count.js +0 -193
  99. package/lib/mongodb/queries/find-by-ids.js +0 -236
  100. package/lib/mongodb/queries/find-one-by-id.js +0 -171
  101. package/lib/mongodb/queries/find-one.js +0 -71
  102. package/lib/mongodb/queries/find-page.js +0 -618
  103. package/lib/mongodb/queries/find.js +0 -171
  104. package/lib/mongodb/queries/index.js +0 -51
  105. package/lib/mongodb/queries/watch.js +0 -538
  106. package/lib/mongodb/writes/common/batch-retry.js +0 -65
  107. package/lib/mongodb/writes/delete-batch.js +0 -323
  108. package/lib/mongodb/writes/delete-many.js +0 -181
  109. package/lib/mongodb/writes/delete-one.js +0 -173
  110. package/lib/mongodb/writes/find-one-and-delete.js +0 -203
  111. package/lib/mongodb/writes/find-one-and-replace.js +0 -239
  112. package/lib/mongodb/writes/find-one-and-update.js +0 -240
  113. package/lib/mongodb/writes/increment-one.js +0 -259
  114. package/lib/mongodb/writes/index.js +0 -46
  115. package/lib/mongodb/writes/insert-batch.js +0 -508
  116. package/lib/mongodb/writes/insert-many.js +0 -223
  117. package/lib/mongodb/writes/insert-one.js +0 -169
  118. package/lib/mongodb/writes/replace-one.js +0 -226
  119. package/lib/mongodb/writes/result-handler.js +0 -237
  120. package/lib/mongodb/writes/update-batch.js +0 -416
  121. package/lib/mongodb/writes/update-many.js +0 -275
  122. package/lib/mongodb/writes/update-one.js +0 -273
  123. package/lib/mongodb/writes/upsert-one.js +0 -203
  124. package/lib/multi-level-cache.js +0 -244
  125. package/lib/operators.js +0 -330
  126. package/lib/redis-cache-adapter.js +0 -267
  127. package/lib/saga/SagaContext.js +0 -67
  128. package/lib/saga/SagaDefinition.js +0 -32
  129. package/lib/saga/SagaExecutor.js +0 -201
  130. package/lib/saga/SagaOrchestrator.js +0 -186
  131. package/lib/saga/index.js +0 -11
  132. package/lib/slow-query-log/base-storage.js +0 -70
  133. package/lib/slow-query-log/batch-queue.js +0 -97
  134. package/lib/slow-query-log/config-manager.js +0 -196
  135. package/lib/slow-query-log/index.js +0 -238
  136. package/lib/slow-query-log/mongodb-storage.js +0 -324
  137. package/lib/slow-query-log/query-hash.js +0 -39
  138. package/lib/sync/ChangeStreamSyncManager.js +0 -405
  139. package/lib/sync/ResumeTokenStore.js +0 -192
  140. package/lib/sync/SyncConfig.js +0 -127
  141. package/lib/sync/SyncTarget.js +0 -240
  142. package/lib/sync/index.js +0 -20
  143. package/lib/transaction/CacheLockManager.js +0 -162
  144. package/lib/transaction/DistributedCacheLockManager.js +0 -475
  145. package/lib/transaction/Transaction.js +0 -315
  146. package/lib/transaction/TransactionManager.js +0 -267
  147. package/lib/transaction/index.js +0 -11
  148. package/lib/utils/objectid-converter.js +0 -632
  149. package/types/README.md +0 -122
  150. package/types/base.ts +0 -94
  151. package/types/batch.ts +0 -187
  152. package/types/cache.ts +0 -71
  153. package/types/chain.ts +0 -254
  154. package/types/collection.ts +0 -357
  155. package/types/expression.ts +0 -109
  156. package/types/function-cache.d.ts +0 -135
  157. package/types/lock.ts +0 -95
  158. package/types/model/definition.ts +0 -152
  159. package/types/model/index.ts +0 -10
  160. package/types/model/instance.ts +0 -121
  161. package/types/model/relations.ts +0 -121
  162. package/types/model/virtuals.ts +0 -32
  163. package/types/monsqlize.ts +0 -245
  164. package/types/options.ts +0 -192
  165. package/types/pagination.ts +0 -154
  166. package/types/pool.ts +0 -125
  167. package/types/query.ts +0 -71
  168. package/types/saga.ts +0 -125
  169. package/types/stream.ts +0 -64
  170. package/types/sync.ts +0 -79
  171. package/types/transaction.ts +0 -79
  172. package/types/write.ts +0 -77
@@ -1,533 +0,0 @@
1
- /**
2
- * 通用函数缓存装饰器
3
- *
4
- * 🆕 v1.1.4: 新增函数缓存功能
5
- * - 缓存任意异步函数的返回结果
6
- * - 支持 TTL 过期
7
- * - 支持自定义键生成
8
- * - 支持命名空间隔离
9
- * - 复用 monSQLize 缓存基础设施
10
- *
11
- * @module lib/function-cache
12
- */
13
-
14
- const CacheFactory = require('./cache');
15
- const crypto = require('crypto');
16
-
17
- // 并发去重映射(防止缓存击穿)
18
- // 使用 Map 存储正在执行的 Promise,带超时清理机制防止内存泄漏
19
- const __inflightFunctions = new Map();
20
-
21
- // 缓存未命中的特殊标记(使用 Symbol 确保唯一性)
22
- const CACHE_MISS = Symbol('CACHE_MISS');
23
-
24
- // 并发请求清理超时时间(毫秒)
25
- const INFLIGHT_CLEANUP_TIMEOUT_MS = 300000; // 5分钟
26
-
27
- // 🔧 v1.1.6: 全局 Map 大小限制和监控
28
- const MAX_INFLIGHT_SIZE = 10000;
29
-
30
- // 定期监控和清理机制
31
- const monitorInterval = setInterval(() => {
32
- const currentSize = __inflightFunctions.size;
33
-
34
- if (currentSize > MAX_INFLIGHT_SIZE) {
35
- console.warn(`[FunctionCache] InflightMap size exceeded: ${currentSize}/${MAX_INFLIGHT_SIZE}`);
36
-
37
- // 清理最旧的 10% 条目
38
- const toDelete = Math.floor(currentSize * 0.1);
39
- let count = 0;
40
- for (const key of __inflightFunctions.keys()) {
41
- if (count++ >= toDelete) break;
42
- __inflightFunctions.delete(key);
43
- }
44
-
45
- console.warn(`[FunctionCache] Cleaned ${toDelete} entries, new size: ${__inflightFunctions.size}`);
46
- }
47
- }, 60000); // 每分钟检查一次
48
-
49
- // 防止阻止进程退出
50
- monitorInterval.unref();
51
-
52
- // 缓存键最大长度(字节)
53
- const MAX_CACHE_KEY_LENGTH = 1024;
54
-
55
- /**
56
- * 基础装饰器:为函数添加缓存能力
57
- *
58
- * @param {Function} fn - 要缓存的异步函数
59
- * @param {Object} options - 缓存配置
60
- * @param {number} [options.ttl=60000] - 缓存时间(毫秒)
61
- * @param {Function} [options.keyBuilder] - 自定义键生成函数
62
- * @param {Object} [options.cache] - 缓存实例(可选)
63
- * @param {string} [options.namespace='fn'] - 命名空间
64
- * @param {Function} [options.condition] - 条件缓存函数
65
- * @param {boolean} [options.enableStats=true] - 启用统计
66
- * @returns {Function} 包装后的函数
67
- *
68
- * @example
69
- * // 基础用法
70
- * const cachedFn = withCache(originalFn, { ttl: 60000 });
71
- * const result = await cachedFn('arg1', 'arg2');
72
- *
73
- * // 自定义键生成
74
- * const cachedFn = withCache(originalFn, {
75
- * ttl: 300000,
76
- * keyBuilder: (userId) => `user:${userId}`
77
- * });
78
- *
79
- * // 条件缓存(只缓存非空结果)
80
- * const cachedFn = withCache(originalFn, {
81
- * ttl: 60000,
82
- * condition: (result) => result && result.length > 0
83
- * });
84
- */
85
- function withCache(fn, options = {}) {
86
- const {
87
- ttl = 60000,
88
- keyBuilder,
89
- cache,
90
- namespace = 'fn',
91
- condition,
92
- enableStats = true
93
- } = options;
94
-
95
- // 参数验证
96
- if (typeof fn !== 'function') {
97
- throw new Error('fn must be a function');
98
- }
99
- if (ttl !== undefined && (typeof ttl !== 'number' || ttl < 0)) {
100
- throw new Error('ttl must be a non-negative number');
101
- }
102
- if (keyBuilder !== undefined && typeof keyBuilder !== 'function') {
103
- throw new Error('keyBuilder must be a function');
104
- }
105
- if (condition !== undefined && typeof condition !== 'function') {
106
- throw new Error('condition must be a function');
107
- }
108
-
109
- // 使用全局缓存或自定义缓存
110
- const cacheInstance = cache || CacheFactory.createDefault();
111
-
112
- // 验证缓存实例
113
- if (!CacheFactory.isValidCache(cacheInstance)) {
114
- throw new Error('Invalid cache instance: must implement CacheLike interface');
115
- }
116
-
117
- // 统计信息
118
- // 注意:在极高并发场景下,统计可能不完全准确(这是性能与精确度的权衡)
119
- const stats = {
120
- hits: 0,
121
- misses: 0,
122
- errors: 0,
123
- totalTime: 0,
124
- calls: 0
125
- };
126
-
127
- // 返回包装后的函数
128
- const wrappedFn = async function(...args) {
129
- // 1. 生成缓存键
130
- let cacheKey;
131
- try {
132
- const baseKey = keyBuilder
133
- ? `${namespace}:${keyBuilder(...args)}`
134
- : `${namespace}:${fn.name}:${CacheFactory.stableStringify(args)}`;
135
-
136
- // 🔧 v1.1.6: 限制缓存键大小
137
- if (baseKey.length > MAX_CACHE_KEY_LENGTH) {
138
- const hash = crypto.createHash('sha256').update(baseKey).digest('hex');
139
- cacheKey = `${namespace}:${fn.name}:hash:${hash}`;
140
- } else {
141
- cacheKey = baseKey;
142
- }
143
- } catch (err) {
144
- // 键生成失败,直接执行原函数
145
- if (enableStats) stats.errors++;
146
- return await fn.apply(this, args);
147
- }
148
-
149
- // 2. 尝试从缓存读取
150
- const startTime = Date.now();
151
- let cached = CACHE_MISS;
152
- try {
153
- // 优化:使用特殊标记来区分"缓存未命中"和"缓存值是 undefined"
154
- const value = await cacheInstance.get(cacheKey);
155
-
156
- // 如果缓存返回 undefined,需要确认是否真的不存在
157
- if (value === undefined) {
158
- // 只在返回 undefined 时才调用 exists 检查
159
- const exists = await cacheInstance.exists(cacheKey);
160
- if (exists) {
161
- cached = undefined; // 缓存的值就是 undefined
162
- }
163
- // 如果 exists 返回 false,cached 保持 CACHE_MISS
164
- } else {
165
- // 非 undefined 值,直接使用
166
- cached = value;
167
- }
168
- } catch (err) {
169
- if (enableStats) stats.errors++;
170
- // 🔧 v1.1.6: 添加错误日志
171
- console.warn('[FunctionCache] Cache get failed:', {
172
- key: cacheKey.substring(0, 100), // 截断避免日志过长
173
- error: err.message
174
- });
175
- }
176
-
177
- if (cached !== CACHE_MISS) {
178
- if (enableStats) {
179
- stats.hits++;
180
- stats.calls++;
181
- stats.totalTime += Date.now() - startTime;
182
- }
183
- return cached;
184
- }
185
-
186
- // 3. 并发控制(防止缓存击穿)
187
- if (__inflightFunctions.has(cacheKey)) {
188
- try {
189
- const result = await __inflightFunctions.get(cacheKey);
190
- if (enableStats) {
191
- stats.hits++;
192
- stats.calls++;
193
- }
194
- return result;
195
- } catch (err) {
196
- // 并发请求失败,继续执行
197
- }
198
- }
199
-
200
- // 4. 执行原函数
201
- const promise = (async () => {
202
- try {
203
- const result = await fn.apply(this, args);
204
-
205
- // 5. 条件缓存
206
- let shouldCache = true;
207
- if (condition) {
208
- try {
209
- shouldCache = condition(result);
210
- } catch (err) {
211
- // 条件函数失败,默认缓存
212
- if (enableStats) stats.errors++;
213
- shouldCache = true;
214
- }
215
- }
216
-
217
- if (shouldCache) {
218
- try {
219
- await cacheInstance.set(cacheKey, result, ttl);
220
- } catch (err) {
221
- if (enableStats) stats.errors++;
222
- // 🔧 v1.1.6: 添加错误日志
223
- console.warn('[FunctionCache] Cache set failed:', {
224
- key: cacheKey.substring(0, 100),
225
- error: err.message
226
- });
227
- }
228
- }
229
-
230
- return result;
231
- } finally {
232
- __inflightFunctions.delete(cacheKey);
233
- }
234
- })();
235
-
236
- __inflightFunctions.set(cacheKey, promise);
237
-
238
- // 🔧 v1.1.4-hotfix: 超时清理机制防止内存泄漏
239
- // 如果 Promise 长时间未完成,自动清理
240
- const cleanupTimeout = setTimeout(() => {
241
- __inflightFunctions.delete(cacheKey);
242
- }, INFLIGHT_CLEANUP_TIMEOUT_MS);
243
-
244
- // Promise 完成后清除定时器
245
- promise.finally(() => {
246
- clearTimeout(cleanupTimeout);
247
- });
248
-
249
- try {
250
- const result = await promise;
251
- if (enableStats) {
252
- stats.misses++;
253
- stats.calls++;
254
- stats.totalTime += Date.now() - startTime;
255
- }
256
- return result;
257
- } catch (err) {
258
- if (enableStats) {
259
- stats.errors++;
260
- stats.calls++;
261
- }
262
- throw err;
263
- }
264
- };
265
-
266
- // 挂载统计方法
267
- wrappedFn.getCacheStats = () => ({
268
- ...stats,
269
- hitRate: stats.hits / (stats.hits + stats.misses) || 0,
270
- avgTime: stats.totalTime / stats.calls || 0
271
- });
272
-
273
- return wrappedFn;
274
- }
275
-
276
- /**
277
- * 函数缓存管理类
278
- *
279
- * @class FunctionCache
280
- *
281
- * @example
282
- * const fnCache = new FunctionCache(msq);
283
- *
284
- * // 注册函数
285
- * fnCache.register('getUserProfile', getUserProfileFn, { ttl: 300000 });
286
- *
287
- * // 执行函数
288
- * const profile = await fnCache.execute('getUserProfile', 'user123');
289
- *
290
- * // 失效缓存
291
- * await fnCache.invalidate('getUserProfile', 'user123');
292
- *
293
- * // 查看统计
294
- * const stats = fnCache.getStats('getUserProfile');
295
- */
296
- class FunctionCache {
297
- /**
298
- * 构造函数
299
- * @param {Object} msq - MonSQLize 实例(可选)
300
- * @param {Object} options - 配置选项
301
- * @param {string} [options.namespace='action'] - 命名空间
302
- * @param {number} [options.defaultTTL=60000] - 默认 TTL(毫秒)
303
- * @param {boolean} [options.enableStats=true] - 启用统计
304
- */
305
- constructor(msq, options = {}) {
306
- // 参数验证
307
- if (options && typeof options !== 'object') {
308
- throw new Error('options must be an object');
309
- }
310
-
311
- this.cache = msq ? msq.getCache() : CacheFactory.createDefault();
312
-
313
- // 验证缓存实例
314
- if (!CacheFactory.isValidCache(this.cache)) {
315
- throw new Error('Invalid cache instance from MonSQLize');
316
- }
317
-
318
- this.functions = new Map();
319
- this.stats = new Map();
320
- this.options = {
321
- namespace: options.namespace || 'action',
322
- defaultTTL: options.defaultTTL || 60000,
323
- enableStats: options.enableStats !== false
324
- };
325
-
326
- // 参数验证
327
- if (typeof this.options.namespace !== 'string') {
328
- throw new Error('namespace must be a string');
329
- }
330
- if (typeof this.options.defaultTTL !== 'number' || this.options.defaultTTL < 0) {
331
- throw new Error('defaultTTL must be a non-negative number');
332
- }
333
- }
334
-
335
- /**
336
- * 注册函数
337
- * @param {string} name - 函数名称
338
- * @param {Function} fn - 函数实现
339
- * @param {Object} options - 缓存配置
340
- * @param {number} [options.ttl] - 缓存过期时间(毫秒)
341
- * @param {Function} [options.keyBuilder] - 自定义键生成函数
342
- * @param {Function} [options.condition] - 条件缓存函数
343
- */
344
- async register(name, fn, options = {}) {
345
- if (!name || typeof name !== 'string') {
346
- throw new Error('Function name must be a non-empty string');
347
- }
348
- if (typeof fn !== 'function') {
349
- throw new Error('fn must be a function');
350
- }
351
- if (options && typeof options !== 'object') {
352
- throw new Error('options must be an object');
353
- }
354
-
355
- const cachedFn = withCache(fn, {
356
- ...options,
357
- cache: this.cache,
358
- namespace: `${this.options.namespace}:${name}`,
359
- ttl: options.ttl !== undefined ? options.ttl : this.options.defaultTTL
360
- });
361
-
362
- this.functions.set(name, cachedFn);
363
-
364
- if (this.options.enableStats) {
365
- this.stats.set(name, {
366
- hits: 0,
367
- misses: 0,
368
- errors: 0,
369
- calls: 0,
370
- totalTime: 0
371
- });
372
- }
373
- }
374
-
375
-
376
- /**
377
- * 执行函数
378
- * @param {string} name - 函数名称
379
- * @param {...any} args - 函数参数
380
- * @returns {Promise<any>}
381
- */
382
- async execute(name, ...args) {
383
- const fn = this.functions.get(name);
384
- if (!fn) {
385
- throw new Error(`Function '${name}' not registered`);
386
- }
387
-
388
- const startTime = Date.now();
389
- try {
390
- const result = await fn(...args);
391
-
392
- if (this.options.enableStats) {
393
- const stats = this.stats.get(name);
394
- if (stats) {
395
- stats.calls++;
396
- stats.totalTime += Date.now() - startTime;
397
- }
398
- }
399
-
400
- return result;
401
- } catch (err) {
402
- if (this.options.enableStats) {
403
- const stats = this.stats.get(name);
404
- if (stats) {
405
- stats.errors++;
406
- stats.calls++;
407
- }
408
- }
409
- throw err;
410
- }
411
- }
412
-
413
- /**
414
- * 失效缓存
415
- * @param {string} name - 函数名称
416
- * @param {...any} args - 函数参数
417
- */
418
- async invalidate(name, ...args) {
419
- if (!name || typeof name !== 'string') {
420
- throw new Error('Function name must be a non-empty string');
421
- }
422
-
423
- const fn = this.functions.get(name);
424
- if (!fn) {
425
- throw new Error(`Function '${name}' not registered`);
426
- }
427
-
428
- // 获取原始函数(从缓存的函数中提取)
429
- const originalFn = fn;
430
-
431
- // 缓存键格式:${namespace}:${name}:${fnName}:${args}
432
- // 但是因为我们在 register 时已经将 name 加入 namespace,
433
- // withCache 会再拼接 fn.name,所以这里需要使用正确的完整键
434
- // 实际键格式:${this.options.namespace}:${name}:${fn.name}:${args}
435
-
436
- // 构建通配符模式来删除所有匹配的缓存
437
- const pattern = `${this.options.namespace}:${name}:*${CacheFactory.stableStringify(args)}*`;
438
- await this.cache.delPattern(pattern);
439
- }
440
-
441
- /**
442
- * 批量失效缓存
443
- * @param {string} pattern - 失效模式(支持通配符 *)
444
- * @returns {Promise<number>} 删除的缓存条目数
445
- */
446
- async invalidatePattern(pattern) {
447
- if (!pattern || typeof pattern !== 'string') {
448
- throw new Error('Pattern must be a non-empty string');
449
- }
450
-
451
- const fullPattern = `${this.options.namespace}:${pattern}`;
452
- return await this.cache.delPattern(fullPattern);
453
- }
454
-
455
- /**
456
- * 获取统计信息
457
- * @param {string} [name] - 函数名称(可选)
458
- * @returns {Object|null}
459
- */
460
- getStats(name) {
461
- if (name) {
462
- const stats = this.stats.get(name);
463
- if (!stats) return null;
464
- return {
465
- ...stats,
466
- hitRate: stats.hits / (stats.hits + stats.misses) || 0,
467
- avgTime: stats.totalTime / stats.calls || 0
468
- };
469
- }
470
-
471
- const allStats = {};
472
- for (const [fnName, stats] of this.stats.entries()) {
473
- allStats[fnName] = {
474
- ...stats,
475
- hitRate: stats.hits / (stats.hits + stats.misses) || 0,
476
- avgTime: stats.totalTime / stats.calls || 0
477
- };
478
- }
479
- return allStats;
480
- }
481
-
482
- /**
483
- * 列出所有已注册的函数
484
- * @returns {string[]}
485
- */
486
- list() {
487
- return Array.from(this.functions.keys());
488
- }
489
-
490
- /**
491
- * 重置统计信息
492
- * @param {string} [name] - 函数名称(可选)
493
- */
494
- resetStats(name) {
495
- if (name) {
496
- const stats = this.stats.get(name);
497
- if (stats) {
498
- Object.assign(stats, {
499
- hits: 0,
500
- misses: 0,
501
- errors: 0,
502
- calls: 0,
503
- totalTime: 0
504
- });
505
- }
506
- } else {
507
- for (const stats of this.stats.values()) {
508
- Object.assign(stats, {
509
- hits: 0,
510
- misses: 0,
511
- errors: 0,
512
- calls: 0,
513
- totalTime: 0
514
- });
515
- }
516
- }
517
- }
518
-
519
- /**
520
- * 清空所有已注册的函数
521
- */
522
- clear() {
523
- this.functions.clear();
524
- this.stats.clear();
525
- }
526
- }
527
-
528
- module.exports = {
529
- withCache,
530
- FunctionCache
531
- };
532
-
533
-