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.
- package/CHANGELOG.md +204 -2464
- package/README.md +735 -1198
- package/index.d.ts +942 -18
- package/lib/cache.js +8 -8
- package/lib/common/validation.js +64 -1
- package/lib/connect.js +3 -3
- package/lib/errors.js +10 -0
- package/lib/index.js +173 -9
- package/lib/infrastructure/ssh-tunnel-ssh2.js +211 -0
- package/lib/infrastructure/ssh-tunnel.js +40 -0
- package/lib/infrastructure/uri-parser.js +35 -0
- package/lib/lock/Lock.js +66 -0
- package/lib/lock/errors.js +27 -0
- package/lib/lock/index.js +12 -0
- package/lib/logger.js +1 -1
- package/lib/model/examples/test.js +225 -29
- package/lib/model/features/soft-delete.js +348 -0
- package/lib/model/features/version.js +156 -0
- package/lib/model/index.js +756 -0
- package/lib/mongodb/common/accessor-helpers.js +17 -3
- package/lib/mongodb/connect.js +68 -13
- package/lib/mongodb/index.js +153 -6
- package/lib/mongodb/management/collection-ops.js +4 -4
- package/lib/mongodb/management/index-ops.js +18 -18
- package/lib/mongodb/management/validation-ops.js +3 -3
- package/lib/mongodb/queries/aggregate.js +14 -5
- package/lib/mongodb/queries/chain.js +52 -45
- package/lib/mongodb/queries/count.js +16 -6
- package/lib/mongodb/queries/distinct.js +15 -6
- package/lib/mongodb/queries/find-and-count.js +22 -13
- package/lib/mongodb/queries/find-by-ids.js +5 -5
- package/lib/mongodb/queries/find-one-by-id.js +1 -1
- package/lib/mongodb/queries/find-one.js +12 -3
- package/lib/mongodb/queries/find-page.js +12 -0
- package/lib/mongodb/queries/find.js +15 -6
- package/lib/mongodb/queries/watch.js +11 -2
- package/lib/mongodb/writes/common/batch-retry.js +64 -0
- package/lib/mongodb/writes/delete-batch.js +322 -0
- package/lib/mongodb/writes/delete-many.js +20 -11
- package/lib/mongodb/writes/delete-one.js +18 -9
- package/lib/mongodb/writes/find-one-and-delete.js +19 -10
- package/lib/mongodb/writes/find-one-and-replace.js +36 -20
- package/lib/mongodb/writes/find-one-and-update.js +36 -20
- package/lib/mongodb/writes/increment-one.js +22 -7
- package/lib/mongodb/writes/index.js +17 -13
- package/lib/mongodb/writes/insert-batch.js +46 -37
- package/lib/mongodb/writes/insert-many.js +22 -13
- package/lib/mongodb/writes/insert-one.js +18 -9
- package/lib/mongodb/writes/replace-one.js +33 -17
- package/lib/mongodb/writes/result-handler.js +14 -14
- package/lib/mongodb/writes/update-batch.js +358 -0
- package/lib/mongodb/writes/update-many.js +34 -18
- package/lib/mongodb/writes/update-one.js +33 -17
- package/lib/mongodb/writes/upsert-one.js +25 -9
- package/lib/operators.js +1 -1
- package/lib/redis-cache-adapter.js +3 -3
- package/lib/slow-query-log/base-storage.js +69 -0
- package/lib/slow-query-log/batch-queue.js +96 -0
- package/lib/slow-query-log/config-manager.js +195 -0
- package/lib/slow-query-log/index.js +237 -0
- package/lib/slow-query-log/mongodb-storage.js +323 -0
- package/lib/slow-query-log/query-hash.js +38 -0
- package/lib/transaction/DistributedCacheLockManager.js +240 -5
- package/lib/transaction/Transaction.js +1 -1
- package/lib/utils/objectid-converter.js +566 -0
- 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<
|
|
495
|
-
findOne(query: any, options: FindOptions & { meta: true | MetaOptions }): Promise<ResultWithMeta<
|
|
496
|
-
findOne(query?: any, options?: FindOptions): Promise<
|
|
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 =
|
|
567
|
-
find<T =
|
|
568
|
-
find<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 =
|
|
577
|
-
aggregate<T =
|
|
578
|
-
aggregate<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
|
|
676
|
-
db
|
|
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.
|
|
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
|
-
|
|
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
|
+
|