monsqlize 1.0.1 → 1.0.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +204 -2464
  2. package/README.md +735 -1198
  3. package/index.d.ts +942 -18
  4. package/lib/cache.js +8 -8
  5. package/lib/common/validation.js +64 -1
  6. package/lib/connect.js +3 -3
  7. package/lib/errors.js +10 -0
  8. package/lib/index.js +173 -9
  9. package/lib/infrastructure/ssh-tunnel-ssh2.js +211 -0
  10. package/lib/infrastructure/ssh-tunnel.js +40 -0
  11. package/lib/infrastructure/uri-parser.js +35 -0
  12. package/lib/lock/Lock.js +66 -0
  13. package/lib/lock/errors.js +27 -0
  14. package/lib/lock/index.js +12 -0
  15. package/lib/logger.js +1 -1
  16. package/lib/model/examples/test.js +225 -29
  17. package/lib/model/features/soft-delete.js +348 -0
  18. package/lib/model/features/version.js +156 -0
  19. package/lib/model/index.js +756 -0
  20. package/lib/mongodb/common/accessor-helpers.js +17 -3
  21. package/lib/mongodb/connect.js +68 -13
  22. package/lib/mongodb/index.js +153 -6
  23. package/lib/mongodb/management/collection-ops.js +4 -4
  24. package/lib/mongodb/management/index-ops.js +18 -18
  25. package/lib/mongodb/management/validation-ops.js +3 -3
  26. package/lib/mongodb/queries/aggregate.js +14 -5
  27. package/lib/mongodb/queries/chain.js +52 -45
  28. package/lib/mongodb/queries/count.js +16 -6
  29. package/lib/mongodb/queries/distinct.js +15 -6
  30. package/lib/mongodb/queries/find-and-count.js +22 -13
  31. package/lib/mongodb/queries/find-by-ids.js +5 -5
  32. package/lib/mongodb/queries/find-one-by-id.js +1 -1
  33. package/lib/mongodb/queries/find-one.js +12 -3
  34. package/lib/mongodb/queries/find-page.js +12 -0
  35. package/lib/mongodb/queries/find.js +15 -6
  36. package/lib/mongodb/queries/watch.js +11 -2
  37. package/lib/mongodb/writes/common/batch-retry.js +64 -0
  38. package/lib/mongodb/writes/delete-batch.js +322 -0
  39. package/lib/mongodb/writes/delete-many.js +20 -11
  40. package/lib/mongodb/writes/delete-one.js +18 -9
  41. package/lib/mongodb/writes/find-one-and-delete.js +19 -10
  42. package/lib/mongodb/writes/find-one-and-replace.js +36 -20
  43. package/lib/mongodb/writes/find-one-and-update.js +36 -20
  44. package/lib/mongodb/writes/increment-one.js +22 -7
  45. package/lib/mongodb/writes/index.js +17 -13
  46. package/lib/mongodb/writes/insert-batch.js +46 -37
  47. package/lib/mongodb/writes/insert-many.js +22 -13
  48. package/lib/mongodb/writes/insert-one.js +18 -9
  49. package/lib/mongodb/writes/replace-one.js +33 -17
  50. package/lib/mongodb/writes/result-handler.js +14 -14
  51. package/lib/mongodb/writes/update-batch.js +358 -0
  52. package/lib/mongodb/writes/update-many.js +34 -18
  53. package/lib/mongodb/writes/update-one.js +33 -17
  54. package/lib/mongodb/writes/upsert-one.js +25 -9
  55. package/lib/operators.js +1 -1
  56. package/lib/redis-cache-adapter.js +3 -3
  57. package/lib/slow-query-log/base-storage.js +69 -0
  58. package/lib/slow-query-log/batch-queue.js +96 -0
  59. package/lib/slow-query-log/config-manager.js +195 -0
  60. package/lib/slow-query-log/index.js +237 -0
  61. package/lib/slow-query-log/mongodb-storage.js +323 -0
  62. package/lib/slow-query-log/query-hash.js +38 -0
  63. package/lib/transaction/DistributedCacheLockManager.js +240 -5
  64. package/lib/transaction/Transaction.js +1 -1
  65. package/lib/utils/objectid-converter.js +566 -0
  66. package/package.json +18 -6
package/index.d.ts CHANGED
@@ -51,6 +51,95 @@ declare module 'monsqlize' {
51
51
  // 事务相关类型定义(Transaction API)
52
52
  // ============================================================================
53
53
 
54
+ /**
55
+ * 业务锁配置选项
56
+ * @since v1.4.0
57
+ */
58
+ interface LockOptions {
59
+ /** 锁过期时间(毫秒),默认 10000 */
60
+ ttl?: number;
61
+ /** 获取锁失败时的重试次数,默认 3 */
62
+ retryTimes?: number;
63
+ /** 重试间隔(毫秒),默认 100 */
64
+ retryDelay?: number;
65
+ /** Redis 不可用时是否降级为无锁执行,默认 false */
66
+ fallbackToNoLock?: boolean;
67
+ }
68
+
69
+ /**
70
+ * 锁对象
71
+ * 表示一个已获取的锁,提供释放和续期方法
72
+ * @since v1.4.0
73
+ */
74
+ interface Lock {
75
+ /** 锁的 Key */
76
+ readonly key: string;
77
+ /** 锁的唯一ID */
78
+ readonly lockId: string;
79
+ /** 是否已释放 */
80
+ readonly released: boolean;
81
+
82
+ /**
83
+ * 释放锁
84
+ * @returns Promise<boolean> 是否成功释放
85
+ */
86
+ release(): Promise<boolean>;
87
+
88
+ /**
89
+ * 续期(延长 TTL)
90
+ * @param ttl - 新的过期时间(毫秒),默认使用原TTL
91
+ * @returns Promise<boolean> 是否成功续期
92
+ */
93
+ renew(ttl?: number): Promise<boolean>;
94
+
95
+ /**
96
+ * 检查锁是否仍被持有
97
+ * @returns boolean
98
+ */
99
+ isHeld(): boolean;
100
+
101
+ /**
102
+ * 获取锁持有时间(毫秒)
103
+ * @returns number
104
+ */
105
+ getHoldTime(): number;
106
+ }
107
+
108
+ /**
109
+ * 锁统计信息
110
+ * @since v1.4.0
111
+ */
112
+ interface LockStats {
113
+ /** 成功获取锁的次数 */
114
+ locksAcquired: number;
115
+ /** 成功释放锁的次数 */
116
+ locksReleased: number;
117
+ /** 锁检查次数 */
118
+ lockChecks: number;
119
+ /** 错误次数 */
120
+ errors: number;
121
+ /** 锁键前缀 */
122
+ lockKeyPrefix: string;
123
+ /** 锁最大持续时间 */
124
+ maxDuration: number;
125
+ }
126
+
127
+ /**
128
+ * 锁获取失败错误
129
+ * @since v1.4.0
130
+ */
131
+ class LockAcquireError extends Error {
132
+ readonly code: 'LOCK_ACQUIRE_FAILED';
133
+ }
134
+
135
+ /**
136
+ * 锁超时错误
137
+ * @since v1.4.0
138
+ */
139
+ class LockTimeoutError extends Error {
140
+ readonly code: 'LOCK_TIMEOUT';
141
+ }
142
+
54
143
  /**
55
144
  * MongoDB 事务会话(原生 ClientSession)
56
145
  * @since v0.2.0
@@ -190,6 +279,33 @@ declare module 'monsqlize' {
190
279
  [k: string]: any;
191
280
  }
192
281
 
282
+ /**
283
+ * SSH 隧道配置
284
+ * @since v1.3.0
285
+ */
286
+ interface SSHConfig {
287
+ /** SSH 服务器地址 */
288
+ host: string;
289
+ /** SSH 服务器端口(默认 22) */
290
+ port?: number;
291
+ /** SSH 用户名 */
292
+ username: string;
293
+ /** SSH 密码(与 privateKey 二选一) */
294
+ password?: string;
295
+ /** SSH 私钥(字符串或 Buffer,与 password 二选一) */
296
+ privateKey?: string | Buffer;
297
+ /** 私钥密码(如果私钥有加密) */
298
+ passphrase?: string;
299
+ /** 连接超时时间(毫秒,默认 30000) */
300
+ readyTimeout?: number;
301
+ /** 保持连接的间隔时间(毫秒,默认 10000) */
302
+ keepaliveInterval?: number;
303
+ /** 目标数据库主机(相对于 SSH 服务器,默认 'localhost') */
304
+ dstHost?: string;
305
+ /** 目标数据库端口(相对于 SSH 服务器) */
306
+ dstPort?: number;
307
+ }
308
+
193
309
  /**
194
310
  * 多层缓存写策略
195
311
  * - both:本地+远端双写(等待远端完成)
@@ -222,6 +338,8 @@ declare module 'monsqlize' {
222
338
  type: DbType;
223
339
  databaseName: string;
224
340
  config: any;
341
+ /** SSH 隧道配置(v1.3.0+) */
342
+ ssh?: SSHConfig;
225
343
  cache?: CacheLike | MemoryCacheOptions | MultiLevelCacheOptions | object;
226
344
  logger?: LoggerLike;
227
345
  maxTimeMS?: number; // 全局默认查询超时(毫秒)
@@ -249,6 +367,40 @@ declare module 'monsqlize' {
249
367
  slowQueryTag?: { event?: string; code?: string };
250
368
  formatSlowQuery?: (meta: any) => any;
251
369
  };
370
+ /**
371
+ * ObjectId 自动转换配置(v1.3.0+)
372
+ * 自动将字符串 _id 转换为 ObjectId
373
+ * @default true(MongoDB)
374
+ * @since v1.3.0
375
+ */
376
+ autoConvertObjectId?: boolean | {
377
+ /** 是否启用(默认 true) */
378
+ enabled?: boolean;
379
+ /** 排除字段列表 */
380
+ excludeFields?: string[];
381
+ /** 自定义字段模式 */
382
+ customFieldPatterns?: string[];
383
+ /** 最大转换深度(默认 10) */
384
+ maxDepth?: number;
385
+ /** 日志级别(默认 'warn') */
386
+ logLevel?: 'info' | 'warn' | 'error';
387
+ };
388
+ /**
389
+ * Count 队列配置(高并发控制)
390
+ * 避免大量并发 count 查询压垮数据库
391
+ * @default { enabled: true, concurrency: CPU核心数 }
392
+ * @since v1.0.0
393
+ */
394
+ countQueue?: boolean | {
395
+ /** 是否启用队列(默认 true) */
396
+ enabled?: boolean;
397
+ /** 并发数(默认 CPU 核心数,最少 4,最多 16) */
398
+ concurrency?: number;
399
+ /** 最大队列长度(默认 10000) */
400
+ maxQueueSize?: number;
401
+ /** 超时时间(毫秒,默认 60000) */
402
+ timeout?: number;
403
+ };
252
404
  }
253
405
  interface FindOptions {
254
406
  projection?: Record<string, any> | string[];
@@ -277,6 +429,189 @@ declare module 'monsqlize' {
277
429
  meta?: boolean | MetaOptions;
278
430
  }
279
431
 
432
+ // ============================================================================
433
+ // 批量操作相关类型定义(Batch Operations)
434
+ // ============================================================================
435
+
436
+ /**
437
+ * insertBatch 选项
438
+ * @since v1.0.0
439
+ */
440
+ interface InsertBatchOptions {
441
+ /** 每批插入的文档数量(默认 1000) */
442
+ batchSize?: number;
443
+ /** 并发批次数(1=串行,>1=并行,默认 1) */
444
+ concurrency?: number;
445
+ /** 批次内是否按顺序插入(默认 false) */
446
+ ordered?: boolean;
447
+ /** 进度回调函数 */
448
+ onProgress?: (progress: BatchProgress) => void;
449
+ /** 错误处理策略: 'stop'|'skip'|'collect'|'retry'(默认 'stop') */
450
+ onError?: 'stop' | 'skip' | 'collect' | 'retry';
451
+ /** 失败批次最大重试次数(onError='retry'时有效,默认 3) */
452
+ retryAttempts?: number;
453
+ /** 重试延迟时间(毫秒,默认 1000) */
454
+ retryDelay?: number;
455
+ /** 重试回调函数 */
456
+ onRetry?: (retryInfo: RetryInfo) => void;
457
+ /** 写确认级别 */
458
+ writeConcern?: { w?: number | string; j?: boolean; wtimeout?: number };
459
+ /** 是否绕过文档验证(默认 false) */
460
+ bypassDocumentValidation?: boolean;
461
+ /** 操作注释(用于日志追踪) */
462
+ comment?: string;
463
+ }
464
+
465
+ /**
466
+ * updateBatch 选项
467
+ * @since v1.0.0
468
+ */
469
+ interface UpdateBatchOptions {
470
+ /** 每批更新的文档数量(默认 1000) */
471
+ batchSize?: number;
472
+ /** 是否预先 count 总数(用于进度百分比,默认 true) */
473
+ estimateProgress?: boolean;
474
+ /** 进度回调函数 */
475
+ onProgress?: (progress: BatchProgress) => void;
476
+ /** 错误处理策略: 'stop'|'skip'|'collect'|'retry'(默认 'stop') */
477
+ onError?: 'stop' | 'skip' | 'collect' | 'retry';
478
+ /** 失败批次最大重试次数(onError='retry'时有效,默认 3) */
479
+ retryAttempts?: number;
480
+ /** 重试延迟时间(毫秒,默认 1000) */
481
+ retryDelay?: number;
482
+ /** 重试回调函数 */
483
+ onRetry?: (retryInfo: RetryInfo) => void;
484
+ /** 写确认级别 */
485
+ writeConcern?: { w?: number | string; j?: boolean; wtimeout?: number };
486
+ /** 未匹配时是否插入(默认 false) */
487
+ upsert?: boolean;
488
+ /** 数组过滤器 */
489
+ arrayFilters?: any[];
490
+ /** 操作注释(用于日志追踪) */
491
+ comment?: string;
492
+ }
493
+
494
+ /**
495
+ * deleteBatch 选项
496
+ * @since v1.0.0
497
+ */
498
+ interface DeleteBatchOptions {
499
+ /** 每批删除的文档数量(默认 1000) */
500
+ batchSize?: number;
501
+ /** 是否预先 count 总数(用于进度百分比,默认 true) */
502
+ estimateProgress?: boolean;
503
+ /** 进度回调函数 */
504
+ onProgress?: (progress: BatchProgress) => void;
505
+ /** 错误处理策略: 'stop'|'skip'|'collect'|'retry'(默认 'stop') */
506
+ onError?: 'stop' | 'skip' | 'collect' | 'retry';
507
+ /** 失败批次最大重试次数(onError='retry'时有效,默认 3) */
508
+ retryAttempts?: number;
509
+ /** 重试延迟时间(毫秒,默认 1000) */
510
+ retryDelay?: number;
511
+ /** 重试回调函数 */
512
+ onRetry?: (retryInfo: RetryInfo) => void;
513
+ /** 写确认级别 */
514
+ writeConcern?: { w?: number | string; j?: boolean; wtimeout?: number };
515
+ /** 操作注释(用于日志追踪) */
516
+ comment?: string;
517
+ }
518
+
519
+ /**
520
+ * 批量操作进度信息
521
+ */
522
+ interface BatchProgress {
523
+ /** 当前批次号(从1开始) */
524
+ currentBatch: number;
525
+ /** 总批次数 */
526
+ totalBatches: number;
527
+ /** 已处理数量 */
528
+ inserted?: number;
529
+ modified?: number;
530
+ deleted?: number;
531
+ /** 总数量 */
532
+ total: number | null;
533
+ /** 完成百分比(0-100) */
534
+ percentage: number | null;
535
+ /** 错误数量 */
536
+ errors: number;
537
+ /** 重试数量 */
538
+ retries: number;
539
+ }
540
+
541
+ /**
542
+ * 重试信息
543
+ */
544
+ interface RetryInfo {
545
+ /** 批次索引(从0开始) */
546
+ batchIndex: number;
547
+ /** 当前重试次数 */
548
+ attempt: number;
549
+ /** 最大重试次数 */
550
+ maxAttempts: number;
551
+ /** 错误信息 */
552
+ error: Error;
553
+ }
554
+
555
+ /**
556
+ * insertBatch 返回结果
557
+ */
558
+ interface InsertBatchResult {
559
+ /** 是否被确认 */
560
+ acknowledged: boolean;
561
+ /** 总文档数 */
562
+ totalCount: number;
563
+ /** 成功插入数 */
564
+ insertedCount: number;
565
+ /** 总批次数 */
566
+ batchCount: number;
567
+ /** 错误列表 */
568
+ errors: Array<{ batchIndex: number; message: string; details?: any }>;
569
+ /** 重试记录列表 */
570
+ retries: Array<{ batchIndex: number; attempts: number; success: boolean }>;
571
+ /** 插入的文档 _id 映射表 */
572
+ insertedIds: Record<number, any>;
573
+ }
574
+
575
+ /**
576
+ * updateBatch 返回结果
577
+ */
578
+ interface UpdateBatchResult {
579
+ /** 是否被确认 */
580
+ acknowledged: boolean;
581
+ /** 总文档数(estimateProgress=true时有值) */
582
+ totalCount: number | null;
583
+ /** 匹配文档数 */
584
+ matchedCount: number;
585
+ /** 成功更新数 */
586
+ modifiedCount: number;
587
+ /** 插入数(upsert=true时) */
588
+ upsertedCount: number;
589
+ /** 总批次数 */
590
+ batchCount: number;
591
+ /** 错误列表 */
592
+ errors: Array<{ batchIndex: number; message: string; details?: any }>;
593
+ /** 重试记录列表 */
594
+ retries: Array<{ batchIndex: number; attempts: number; success: boolean }>;
595
+ }
596
+
597
+ /**
598
+ * deleteBatch 返回结果
599
+ */
600
+ interface DeleteBatchResult {
601
+ /** 是否被确认 */
602
+ acknowledged: boolean;
603
+ /** 总文档数(estimateProgress=true时有值) */
604
+ totalCount: number | null;
605
+ /** 成功删除数 */
606
+ deletedCount: number;
607
+ /** 总批次数 */
608
+ batchCount: number;
609
+ /** 错误列表 */
610
+ errors: Array<{ batchIndex: number; message: string; details?: any }>;
611
+ /** 重试记录列表 */
612
+ retries: Array<{ batchIndex: number; attempts: number; success: boolean }>;
613
+ }
614
+
280
615
  interface AggregateOptions {
281
616
  cache?: number; // 缓存时间(毫秒),默认 0(不缓存)
282
617
  maxTimeMS?: number; // 查询超时时间(毫秒)
@@ -302,6 +637,16 @@ declare module 'monsqlize' {
302
637
  wtimeout?: number; // 写超时时间(毫秒)
303
638
  }
304
639
 
640
+ /**
641
+ * 简化的插入选项(用于简化调用形式)
642
+ */
643
+ interface InsertOneSimplifiedOptions {
644
+ writeConcern?: WriteConcern; // 写确认级别(可选)
645
+ bypassDocumentValidation?: boolean; // 跳过文档验证(可选)
646
+ comment?: string; // 查询注释(用于生产环境日志跟踪)
647
+ session?: any; // 事务会话
648
+ }
649
+
305
650
  interface InsertOneOptions {
306
651
  document: any; // 要插入的文档
307
652
  writeConcern?: WriteConcern; // 写确认级别(可选)
@@ -314,6 +659,17 @@ declare module 'monsqlize' {
314
659
  insertedId: any; // 插入的文档 _id
315
660
  }
316
661
 
662
+ /**
663
+ * 简化的批量插入选项(用于简化调用形式)
664
+ */
665
+ interface InsertManySimplifiedOptions {
666
+ ordered?: boolean; // 是否有序插入(默认 true)
667
+ writeConcern?: WriteConcern; // 写确认级别(可选)
668
+ bypassDocumentValidation?: boolean; // 跳过文档验证(可选)
669
+ comment?: string; // 查询注释(用于生产环境日志跟踪)
670
+ session?: any; // 事务会话
671
+ }
672
+
317
673
  interface InsertManyOptions {
318
674
  documents: any[]; // 要插入的文档数组
319
675
  ordered?: boolean; // 是否有序插入(默认 true)
@@ -484,16 +840,16 @@ declare module 'monsqlize' {
484
840
  driver?: { connected: boolean };
485
841
  }
486
842
 
487
- interface CollectionAccessor {
843
+ interface CollectionAccessor<TSchema = any> {
488
844
  getNamespace(): { iid: string; type: string; db: string; collection: string };
489
845
  dropCollection(): Promise<boolean>;
490
846
  createCollection(name?: string | null, options?: any): Promise<boolean>;
491
847
  createView(viewName: string, source: string, pipeline?: any[]): Promise<boolean>;
492
848
 
493
- // findOne 重载:支持 meta 参数
494
- findOne(query?: any, options?: Omit<FindOptions, 'meta'>): Promise<any | null>;
495
- findOne(query: any, options: FindOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<any | null>>;
496
- findOne(query?: any, options?: FindOptions): Promise<any | null | ResultWithMeta<any | null>>;
849
+ // findOne 重载:支持 meta 参数和泛型
850
+ findOne<T = TSchema>(query?: any, options?: Omit<FindOptions, 'meta'>): Promise<T | null>;
851
+ findOne<T = TSchema>(query: any, options: FindOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<T | null>>;
852
+ findOne<T = TSchema>(query?: any, options?: FindOptions): Promise<T | null | ResultWithMeta<T | null>>;
497
853
 
498
854
  /**
499
855
  * 通过 _id 查询单个文档(便利方法)
@@ -518,7 +874,7 @@ declare module 'monsqlize' {
518
874
  */
519
875
  findOneById(id: string | any, options?: Omit<FindOptions, 'meta'>): Promise<any | null>;
520
876
 
521
- u /**
877
+ u /**
522
878
  * 批量通过 _id 查询多个文档(便利方法)
523
879
  * @param ids - _id 数组(支持字符串和 ObjectId 混合)
524
880
  * @param options - 查询选项
@@ -563,9 +919,9 @@ u /**
563
919
  ): Promise<any[]>;
564
920
 
565
921
  // find 重载:支持 meta 参数和链式调用 (v2.0+)
566
- find<T = any>(query?: any): FindChain<T>;
567
- find<T = any>(query: any, options: FindOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<T[]>>;
568
- find<T = any>(query?: any, options?: FindOptions): Promise<T[]> | FindChain<T> | ResultWithMeta<T[]>;
922
+ find<T = TSchema>(query?: any): FindChain<T>;
923
+ find<T = TSchema>(query: any, options: FindOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<T[]>>;
924
+ find<T = TSchema>(query?: any, options?: FindOptions): Promise<T[]> | FindChain<T> | ResultWithMeta<T[]>;
569
925
 
570
926
  // count 重载:支持 meta 参数
571
927
  count(query?: any, options?: Omit<CountOptions, 'meta'>): Promise<number>;
@@ -573,9 +929,9 @@ u /**
573
929
  count(query?: any, options?: CountOptions): Promise<number | ResultWithMeta<number>>;
574
930
 
575
931
  // aggregate 重载:支持 meta 参数和链式调用 (v2.0+)
576
- aggregate<T = any>(pipeline?: any[]): AggregateChain<T>;
577
- aggregate<T = any>(pipeline: any[], options: AggregateOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<T[]>>;
578
- aggregate<T = any>(pipeline?: any[], options?: AggregateOptions): Promise<T[]> | AggregateChain<T> | ResultWithMeta<T[]>;
932
+ aggregate<T = TSchema>(pipeline?: any[]): AggregateChain<T>;
933
+ aggregate<T = TSchema>(pipeline: any[], options: AggregateOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<T[]>>;
934
+ aggregate<T = TSchema>(pipeline?: any[], options?: AggregateOptions): Promise<T[]> | AggregateChain<T> | ResultWithMeta<T[]>;
579
935
 
580
936
  // distinct 重载:支持 meta 参数
581
937
  distinct<T = any>(field: string, query?: any, options?: Omit<DistinctOptions, 'meta'>): Promise<T[]>;
@@ -594,10 +950,13 @@ u /**
594
950
  clearBookmarks(keyDims?: BookmarkKeyDims): Promise<ClearBookmarksResult>;
595
951
 
596
952
  // findPage:已在 PageResult 中包含 meta 字段,无需重载
597
- findPage(options: FindPageOptions): Promise<PageResult>;
953
+ findPage<T = TSchema>(options: FindPageOptions): Promise<PageResult<T>>;
598
954
 
599
- // 写入操作
955
+ // 写入操作 - 支持简化调用和完整配置
956
+ insertOne<T = TSchema>(document: T, options?: InsertOneSimplifiedOptions): Promise<InsertOneResult>;
600
957
  insertOne(options: InsertOneOptions): Promise<InsertOneResult>;
958
+
959
+ insertMany<T = TSchema>(documents: T[], options?: InsertManySimplifiedOptions): Promise<InsertManyResult>;
601
960
  insertMany(options: InsertManyOptions): Promise<InsertManyResult>;
602
961
 
603
962
  /**
@@ -669,11 +1028,89 @@ u /**
669
1028
  }>;
670
1029
 
671
1030
  invalidate(op?: 'find' | 'findOne' | 'count' | 'findPage' | 'aggregate' | 'distinct'): Promise<number>;
1031
+
1032
+ // ============================================================================
1033
+ // 批量操作方法 (Batch Operations)
1034
+ // ============================================================================
1035
+
1036
+ /**
1037
+ * 大批量插入(自动分批+重试)
1038
+ * @param documents - 要插入的文档数组
1039
+ * @param options - 批量插入选项
1040
+ * @returns Promise<InsertBatchResult>
1041
+ * @since v1.0.0
1042
+ * @example
1043
+ * const result = await collection('products').insertBatch(largeDataset, {
1044
+ * batchSize: 1000,
1045
+ * onProgress: (p) => console.log(`${p.percentage}%`)
1046
+ * });
1047
+ */
1048
+ insertBatch<T = TSchema>(documents: T[], options?: InsertBatchOptions): Promise<InsertBatchResult>;
1049
+
1050
+ /**
1051
+ * 批量更新文档(流式查询+分批更新)
1052
+ * @param filter - 查询条件
1053
+ * @param update - 更新操作(必须使用更新操作符)
1054
+ * @param options - 批量更新选项
1055
+ * @returns Promise<UpdateBatchResult>
1056
+ * @since v1.0.0
1057
+ * @example
1058
+ * const result = await collection('users').updateBatch(
1059
+ * { status: 'pending' },
1060
+ * { $set: { status: 'processed' } },
1061
+ * { batchSize: 5000, onError: 'retry' }
1062
+ * );
1063
+ */
1064
+ updateBatch(
1065
+ filter: Record<string, any>,
1066
+ update: Record<string, any>,
1067
+ options?: UpdateBatchOptions
1068
+ ): Promise<UpdateBatchResult>;
1069
+
1070
+ /**
1071
+ * 批量删除文档(流式查询+分批删除)
1072
+ * @param filter - 查询条件
1073
+ * @param options - 批量删除选项
1074
+ * @returns Promise<DeleteBatchResult>
1075
+ * @since v1.0.0
1076
+ * @example
1077
+ * const result = await collection('logs').deleteBatch(
1078
+ * { createdAt: { $lt: expireDate } },
1079
+ * { batchSize: 5000, estimateProgress: true }
1080
+ * );
1081
+ */
1082
+ deleteBatch(
1083
+ filter: Record<string, any>,
1084
+ options?: DeleteBatchOptions
1085
+ ): Promise<DeleteBatchResult>;
1086
+
1087
+ /**
1088
+ * 查询文档并返回总数(便利方法)
1089
+ * @param filter - 查询条件
1090
+ * @param options - 查询选项
1091
+ * @returns Promise<{ documents: T[], total: number }>
1092
+ * @since v1.0.0
1093
+ * @example
1094
+ * const { documents, total } = await collection('users').findAndCount(
1095
+ * { status: 'active' },
1096
+ * { limit: 10, cache: 60000 }
1097
+ * );
1098
+ */
1099
+ findAndCount<T = TSchema>(
1100
+ filter?: Record<string, any>,
1101
+ options?: FindOptions
1102
+ ): Promise<{ documents: T[]; total: number }>;
672
1103
  }
673
1104
 
1105
+ /**
1106
+ * Collection 类型别名(与 CollectionAccessor 等价)
1107
+ * @since v1.0.4
1108
+ */
1109
+ type Collection<TSchema = any> = CollectionAccessor<TSchema>;
1110
+
674
1111
  type DbAccessor = {
675
- collection: (name: string) => CollectionAccessor;
676
- db: (dbName: string) => { collection: (name: string) => CollectionAccessor };
1112
+ collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
1113
+ db(dbName: string): { collection<TSchema = any>(name: string): CollectionAccessor<TSchema> };
677
1114
  };
678
1115
 
679
1116
  export default class MonSQLize {
@@ -713,13 +1150,53 @@ u /**
713
1150
  /** 健康检查 */
714
1151
  health(): Promise<HealthView>;
715
1152
 
1153
+ /**
1154
+ * 获取慢查询日志(持久化存储)
1155
+ * @param filter - 查询条件(可选)
1156
+ * @param options - 查询选项(可选)
1157
+ * @returns 慢查询日志数组
1158
+ * @since v1.3.1
1159
+ * @example
1160
+ * // 查询所有慢查询
1161
+ * const logs = await msq.getSlowQueryLogs({}, { limit: 10 });
1162
+ *
1163
+ * // 按collection过滤
1164
+ * const userLogs = await msq.getSlowQueryLogs(
1165
+ * { collection: 'users' },
1166
+ * { sort: { count: -1 }, limit: 10 }
1167
+ * );
1168
+ *
1169
+ * // 按操作类型过滤
1170
+ * const findLogs = await msq.getSlowQueryLogs({ operation: 'find' });
1171
+ */
1172
+ getSlowQueryLogs(
1173
+ filter?: Record<string, any>,
1174
+ options?: {
1175
+ sort?: Record<string, 1 | -1>;
1176
+ limit?: number;
1177
+ skip?: number;
1178
+ }
1179
+ ): Promise<Array<{
1180
+ queryHash: string;
1181
+ database: string;
1182
+ collection: string;
1183
+ operation: string;
1184
+ count: number;
1185
+ totalTimeMs: number;
1186
+ avgTimeMs: number;
1187
+ maxTimeMs: number;
1188
+ minTimeMs: number;
1189
+ firstSeen: Date;
1190
+ lastSeen: Date;
1191
+ }>>;
1192
+
716
1193
  /**
717
1194
  * 创建手动事务会话
718
1195
  * @param options - 事务选项
719
1196
  * @returns Transaction 实例
720
1197
  * @since v0.2.0
721
1198
  * @example
722
- * const tx = await msq.startTransaction();
1199
+ * const tx = await msq.startSession();
723
1200
  * try {
724
1201
  * await collection('users').updateOne({...}, {...}, { session: tx.session });
725
1202
  * await tx.commit();
@@ -727,7 +1204,7 @@ u /**
727
1204
  * await tx.abort();
728
1205
  * }
729
1206
  */
730
- startTransaction(options?: TransactionOptions): Promise<Transaction>;
1207
+ startSession(options?: TransactionOptions): Promise<Transaction>;
731
1208
 
732
1209
  /**
733
1210
  * 自动管理事务生命周期(推荐)
@@ -745,6 +1222,90 @@ u /**
745
1222
  callback: (transaction: Transaction) => Promise<T>,
746
1223
  options?: TransactionOptions
747
1224
  ): Promise<T>;
1225
+
1226
+ // ============================================================================
1227
+ // 业务锁 API (v1.4.0+)
1228
+ // ============================================================================
1229
+
1230
+ /**
1231
+ * 业务锁:自动管理锁生命周期(推荐)
1232
+ * @param key - 锁的唯一标识
1233
+ * @param callback - 获取锁后执行的函数
1234
+ * @param options - 锁选项
1235
+ * @returns callback 的返回值
1236
+ * @since v1.4.0
1237
+ * @example
1238
+ * // 库存扣减
1239
+ * await db.withLock('inventory:SKU123', async () => {
1240
+ * const product = await inventory.findOne({ sku: 'SKU123' });
1241
+ * if (product.stock >= 1) {
1242
+ * await inventory.updateOne({ sku: 'SKU123' }, { $inc: { stock: -1 } });
1243
+ * }
1244
+ * });
1245
+ */
1246
+ withLock?<T = any>(
1247
+ key: string,
1248
+ callback: () => Promise<T>,
1249
+ options?: LockOptions
1250
+ ): Promise<T>;
1251
+
1252
+ /**
1253
+ * 业务锁:手动获取锁(阻塞重试)
1254
+ * @param key - 锁的唯一标识
1255
+ * @param options - 锁选项
1256
+ * @returns Lock 对象
1257
+ * @since v1.4.0
1258
+ * @example
1259
+ * const lock = await db.acquireLock('resource:123', { ttl: 5000 });
1260
+ * try {
1261
+ * // 业务逻辑
1262
+ * } finally {
1263
+ * await lock.release();
1264
+ * }
1265
+ */
1266
+ acquireLock?(key: string, options?: LockOptions): Promise<Lock>;
1267
+
1268
+ /**
1269
+ * 业务锁:尝试获取锁(不阻塞)
1270
+ * @param key - 锁的唯一标识
1271
+ * @param options - 锁选项(不包含 retryTimes)
1272
+ * @returns Lock 对象或 null
1273
+ * @since v1.4.0
1274
+ * @example
1275
+ * const lock = await db.tryAcquireLock('resource:123');
1276
+ * if (lock) {
1277
+ * try {
1278
+ * // 业务逻辑
1279
+ * } finally {
1280
+ * await lock.release();
1281
+ * }
1282
+ * } else {
1283
+ * console.log('资源被占用');
1284
+ * }
1285
+ */
1286
+ tryAcquireLock?(key: string, options?: Omit<LockOptions, 'retryTimes'>): Promise<Lock | null>;
1287
+
1288
+ /**
1289
+ * 获取锁统计信息
1290
+ * @returns 锁统计信息
1291
+ * @since v1.4.0
1292
+ * @example
1293
+ * const stats = db.getLockStats();
1294
+ * console.log(stats.locksAcquired, stats.locksReleased);
1295
+ */
1296
+ getLockStats?(): LockStats;
1297
+
1298
+ /**
1299
+ * 创建 Redis 缓存适配器(静态方法)
1300
+ * @param client - Redis 客户端实例(ioredis)
1301
+ * @param options - 可选配置
1302
+ * @returns Redis 缓存适配器实例
1303
+ * @example
1304
+ * const Redis = require('ioredis');
1305
+ * const redis = new Redis();
1306
+ * const redisCache = MonSQLize.createRedisCacheAdapter(redis);
1307
+ */
1308
+ static createRedisCacheAdapter(client: any, options?: any): CacheLike;
748
1309
  }
749
1310
 
750
1311
  // ============================================================================
@@ -1049,4 +1610,367 @@ u /**
1049
1610
  */
1050
1611
  finally(onfinally?: (() => void) | null): Promise<T[]>;
1051
1612
  }
1613
+
1614
+ // ============================================================================
1615
+ // Model 层类型定义(Model API)
1616
+ // @since v1.0.3
1617
+ // ============================================================================
1618
+
1619
+ /**
1620
+ * Schema DSL 函数类型
1621
+ */
1622
+ type SchemaDSL = (dsl: any) => any;
1623
+
1624
+ /**
1625
+ * Model 定义配置
1626
+ */
1627
+ interface ModelDefinition<T = any> {
1628
+ /**
1629
+ * 枚举配置(可被 schema 引用)
1630
+ * @example
1631
+ * enums: {
1632
+ * role: 'admin|user|guest',
1633
+ * status: 'active|inactive'
1634
+ * }
1635
+ */
1636
+ enums?: Record<string, string>;
1637
+
1638
+ /**
1639
+ * Schema 定义(数据验证规则)
1640
+ * 使用 function 时,this 自动绑定到 definition,可访问 this.enums
1641
+ *
1642
+ * @param dsl - schema-dsl 函数
1643
+ * @returns Schema 对象
1644
+ *
1645
+ * @example
1646
+ * // 使用 function(推荐)
1647
+ * schema: function(dsl) {
1648
+ * return dsl({
1649
+ * username: 'string:3-32!',
1650
+ * role: this.enums.role.default('user')
1651
+ * });
1652
+ * }
1653
+ *
1654
+ * // 使用箭头函数
1655
+ * schema: (dsl) => dsl({
1656
+ * username: 'string:3-32!',
1657
+ * email: 'email!'
1658
+ * })
1659
+ */
1660
+ schema: SchemaDSL | ((this: ModelDefinition<T>, dsl: SchemaDSL) => any);
1661
+
1662
+ /**
1663
+ * 自定义方法
1664
+ *
1665
+ * @param model - ModelInstance 实例
1666
+ * @returns 包含 instance 和 static 方法的对象
1667
+ *
1668
+ * @example
1669
+ * methods: (model) => ({
1670
+ * instance: {
1671
+ * checkPassword(password: string) {
1672
+ * return this.password === password;
1673
+ * }
1674
+ * },
1675
+ * static: {
1676
+ * async findByUsername(username: string) {
1677
+ * return await model.findOne({ username });
1678
+ * }
1679
+ * }
1680
+ * })
1681
+ */
1682
+ methods?: (model: ModelInstance<T>) => {
1683
+ instance?: Record<string, Function>;
1684
+ static?: Record<string, Function>;
1685
+ };
1686
+
1687
+ /**
1688
+ * 生命周期钩子
1689
+ *
1690
+ * @param model - ModelInstance 实例
1691
+ * @returns 包含各操作钩子的对象
1692
+ *
1693
+ * @example
1694
+ * hooks: (model) => ({
1695
+ * insert: {
1696
+ * before: async (ctx, docs) => {
1697
+ * ctx.timestamp = Date.now();
1698
+ * return { ...docs, createdAt: new Date() };
1699
+ * },
1700
+ * after: async (ctx, result) => {
1701
+ * console.log('插入耗时:', Date.now() - ctx.timestamp);
1702
+ * }
1703
+ * }
1704
+ * })
1705
+ */
1706
+ hooks?: (model: ModelInstance<T>) => {
1707
+ find?: {
1708
+ before?: (ctx: HookContext, options: any) => void | Promise<void>;
1709
+ after?: (ctx: HookContext, result: any) => any | Promise<any>;
1710
+ };
1711
+ insert?: {
1712
+ before?: (ctx: HookContext, docs: any) => any | Promise<any>;
1713
+ after?: (ctx: HookContext, result: any) => void | Promise<void>;
1714
+ };
1715
+ update?: {
1716
+ before?: (ctx: HookContext, filter: any, update: any) => [any, any] | Promise<[any, any]>;
1717
+ after?: (ctx: HookContext, result: any) => void | Promise<void>;
1718
+ };
1719
+ delete?: {
1720
+ before?: (ctx: HookContext, filter: any) => void | Promise<void>;
1721
+ after?: (ctx: HookContext, result: any) => void | Promise<void>;
1722
+ };
1723
+ };
1724
+
1725
+ /**
1726
+ * 索引定义(自动创建)
1727
+ *
1728
+ * @example
1729
+ * indexes: [
1730
+ * { key: { username: 1 }, unique: true },
1731
+ * { key: { email: 1 }, unique: true },
1732
+ * { key: { status: 1, createdAt: -1 } }
1733
+ * ]
1734
+ */
1735
+ indexes?: Array<{
1736
+ key: Record<string, 1 | -1>;
1737
+ unique?: boolean;
1738
+ sparse?: boolean;
1739
+ expireAfterSeconds?: number;
1740
+ [key: string]: any;
1741
+ }>;
1742
+
1743
+ /**
1744
+ * 关系定义(预留,未完全实现)
1745
+ */
1746
+ relations?: Record<string, {
1747
+ type: 'hasOne' | 'hasMany' | 'belongsTo';
1748
+ target: string;
1749
+ foreignKey: string;
1750
+ }>;
1751
+
1752
+ /**
1753
+ * Model 选项配置
1754
+ * @since v1.0.3
1755
+ */
1756
+ options?: {
1757
+ /**
1758
+ * 自动时间戳
1759
+ * 启用后自动管理 createdAt 和 updatedAt 字段
1760
+ *
1761
+ * @example
1762
+ * // 简单模式:启用默认字段名
1763
+ * options: { timestamps: true }
1764
+ *
1765
+ * // 自定义字段名
1766
+ * options: {
1767
+ * timestamps: {
1768
+ * createdAt: 'created_time',
1769
+ * updatedAt: 'updated_time'
1770
+ * }
1771
+ * }
1772
+ *
1773
+ * // 只启用其中一个
1774
+ * options: {
1775
+ * timestamps: {
1776
+ * createdAt: true,
1777
+ * updatedAt: false
1778
+ * }
1779
+ * }
1780
+ */
1781
+ timestamps?: boolean | {
1782
+ /** 创建时间字段名,false 表示禁用 */
1783
+ createdAt?: boolean | string;
1784
+ /** 更新时间字段名,false 表示禁用 */
1785
+ updatedAt?: boolean | string;
1786
+ };
1787
+
1788
+ /**
1789
+ * 是否启用 Schema 验证(默认 true)
1790
+ * @since v1.0.3
1791
+ */
1792
+ schemaValidation?: boolean;
1793
+
1794
+ /**
1795
+ * 是否启用严格模式(不允许未定义的字段,默认 false)
1796
+ * @since v1.0.3
1797
+ */
1798
+ strict?: boolean;
1799
+
1800
+ /**
1801
+ * 自定义错误消息
1802
+ * @since v1.0.3
1803
+ */
1804
+ messages?: Record<string, string>;
1805
+ };
1806
+ }
1807
+
1808
+ /**
1809
+ * Hook 上下文
1810
+ * 用于在 before 和 after 钩子之间传递数据
1811
+ */
1812
+ interface HookContext {
1813
+ [key: string]: any;
1814
+ }
1815
+
1816
+ /**
1817
+ * 数据验证结果
1818
+ */
1819
+ interface ValidationResult {
1820
+ /** 是否验证通过 */
1821
+ valid: boolean;
1822
+ /** 错误列表 */
1823
+ errors: Array<{
1824
+ field: string;
1825
+ message: string;
1826
+ value?: any;
1827
+ }>;
1828
+ /** 验证后的数据 */
1829
+ data: any;
1830
+ }
1831
+
1832
+ /**
1833
+ * Model 类(静态方法)
1834
+ */
1835
+ class Model {
1836
+ /**
1837
+ * 注册一个 Model 定义
1838
+ *
1839
+ * @param collectionName - 集合名称
1840
+ * @param definition - Model 定义对象
1841
+ * @throws {Error} 集合名称无效、schema 未定义、Model 已存在
1842
+ *
1843
+ * @example
1844
+ * Model.define('users', {
1845
+ * schema: (dsl) => dsl({
1846
+ * username: 'string:3-32!',
1847
+ * email: 'email!'
1848
+ * }),
1849
+ * methods: (model) => ({
1850
+ * instance: {
1851
+ * checkPassword(password) {
1852
+ * return this.password === password;
1853
+ * }
1854
+ * }
1855
+ * })
1856
+ * });
1857
+ */
1858
+ static define<T = any>(collectionName: string, definition: ModelDefinition<T>): void;
1859
+
1860
+ /**
1861
+ * 获取已注册的 Model 定义
1862
+ *
1863
+ * @param collectionName - 集合名称
1864
+ * @returns Model 定义对象,如果不存在返回 undefined
1865
+ */
1866
+ static get<T = any>(collectionName: string): ModelDefinition<T> | undefined;
1867
+
1868
+ /**
1869
+ * 检查 Model 是否已注册
1870
+ *
1871
+ * @param collectionName - 集合名称
1872
+ * @returns 是否已注册
1873
+ */
1874
+ static has(collectionName: string): boolean;
1875
+
1876
+ /**
1877
+ * 列出所有已注册的 Model 名称
1878
+ *
1879
+ * @returns Model 名称数组
1880
+ */
1881
+ static list(): string[];
1882
+
1883
+ /**
1884
+ * 清空所有已注册的 Model(仅测试用)
1885
+ * @private
1886
+ */
1887
+ static _clear(): void;
1888
+ }
1889
+
1890
+ /**
1891
+ * ModelInstance 类
1892
+ * 继承 collection 的所有方法,并扩展 Model 特性
1893
+ */
1894
+ interface ModelInstance<T = any> extends Collection<T> {
1895
+ /** 关联的 collection 对象 */
1896
+ readonly collection: Collection<T>;
1897
+
1898
+ /** Model 定义对象 */
1899
+ readonly definition: ModelDefinition<T>;
1900
+
1901
+ /** monSQLize 实例 */
1902
+ readonly msq: MonSQLize;
1903
+
1904
+ /**
1905
+ * 验证数据是否符合 schema 定义
1906
+ *
1907
+ * @param data - 待验证的数据
1908
+ * @param options - 验证选项
1909
+ * @returns 验证结果
1910
+ *
1911
+ * @example
1912
+ * const result = User.validate({
1913
+ * username: 'test',
1914
+ * email: 'test@example.com'
1915
+ * });
1916
+ *
1917
+ * if (!result.valid) {
1918
+ * console.error('验证失败:', result.errors);
1919
+ * }
1920
+ */
1921
+ validate(data: any, options?: { locale?: 'zh-CN' | 'en-US' }): ValidationResult;
1922
+ }
1923
+
1924
+ /**
1925
+ * 扩展 MonSQLize 类,添加 model 方法
1926
+ */
1927
+ interface MonSQLize {
1928
+ /**
1929
+ * 获取已注册的 Model 实例
1930
+ *
1931
+ * @param collectionName - 集合名称
1932
+ * @returns ModelInstance 实例
1933
+ * @throws {Error} 数据库未连接、Model 未定义
1934
+ *
1935
+ * @example
1936
+ * const User = msq.model('users');
1937
+ *
1938
+ * // 使用继承的 collection 方法
1939
+ * const users = await User.find({ status: 'active' });
1940
+ *
1941
+ * // 使用自定义静态方法
1942
+ * const admin = await User.findByUsername('admin');
1943
+ *
1944
+ * // 使用实例方法
1945
+ * const user = await User.findOne({ username: 'test' });
1946
+ * if (user.checkPassword('secret')) {
1947
+ * console.log('登录成功');
1948
+ * }
1949
+ */
1950
+ model<T = any>(collectionName: string): ModelInstance<T>;
1951
+
1952
+ /**
1953
+ * Model 类引用
1954
+ */
1955
+ Model: typeof Model;
1956
+ }
1957
+
1958
+ /**
1959
+ * 导出 Model 类
1960
+ */
1961
+ export { Model };
1962
+
1963
+ /**
1964
+ * 导出锁错误类型
1965
+ * @since v1.4.0
1966
+ */
1967
+ export { LockAcquireError, LockTimeoutError };
1968
+
1969
+ /**
1970
+ * 导出类型别名
1971
+ * @since v1.0.4
1972
+ */
1973
+ export type { Collection, CollectionAccessor };
1052
1974
  }
1975
+
1976
+