monsqlize 1.2.1 → 1.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # 变更日志 (CHANGELOG)
2
2
 
3
3
  > **说明**: 版本概览摘要,详细变更见 [changelogs/](./changelogs/) 目录
4
- > **最后更新**: 2026-04-13
4
+ > **最后更新**: 2026-04-26
5
5
 
6
6
  ---
7
7
 
@@ -9,6 +9,8 @@
9
9
 
10
10
  | 版本 | 日期 | 变更摘要 | 详细 |
11
11
  |------|------|---------|------|
12
+ | [v1.2.3](./changelogs/v1.2.3.md) | 2026-04-26 | 🐛 **Bug Fix**:`model()` 方法修复注册 key 直接作为 MongoDB 集合名的问题,优先读 `definition.collection > definition.name`,注册 key 仅作 fallback,向后兼容 | [查看](./changelogs/v1.2.3.md) |
13
+ | [v1.2.2](./changelogs/v1.2.2.md) | 2026-04-24 | 🆕 **新功能**:Model 数据源绑定 — `connection: { pool?, database? }` 支持 Model 绑定指定连接池和/或数据库,四种组合路由,向后兼容;🐛 **Bug Fix**:修复 `Model._clear()` 导致 `msq.model()` 实例缓存失效失效,populate 关系丢失问题 | [查看](./changelogs/v1.2.2.md) |
12
14
  | [v1.2.1](./changelogs/v1.2.1.md) | 2026-04-13 | 🐛 **Bug 修复**:`msq.model()` 实例缓存 + 索引去重 + 死代码清理 + `types/monsqlize.ts` 补全 `model()` / `collection()` 类型 | [查看](./changelogs/v1.2.1.md) |
13
15
  | [v1.2.0](./changelogs/v1.2.0.md) | 2026-04-13 | 🐛 **Bug 修复 + 新功能**:`findPage` 正式支持 `projection` 投影参数(修复静默忽略问题)+ 有效投影策略自动保护游标排序字段 + 8 个测试用例 | [查看](./changelogs/v1.2.0.md) |
14
16
  | [v1.1.9](./changelogs/v1.1.9.md) | 2026-04-02 | 🚨 **P1 Bug 修复**:MultiLevelCache L2→L1 回填 TTL 缺失(null 永久驻留 L1)+ 新增 `backfillLocalTTL` 配置 + Redis `getWithTTL` 方法 + 14 个回归测试 | [查看](./changelogs/v1.1.9.md) |
package/README.md CHANGED
@@ -314,78 +314,102 @@ await msq.close();
314
314
 
315
315
  > **📦 依赖说明**: Model 层需要 `schema-dsl` 包支持(已随 monsqlize 自动安装,无需额外操作)
316
316
 
317
+ Model 层有两种使用方式,二者**互斥**,选其一即可:
318
+
319
+ | 方式 | 适合场景 |
320
+ |------|---------|
321
+ | **手动注册**(`Model.define()`)| 少量 Model、测试环境、需要精确控制加载顺序 |
322
+ | **自动加载**(`models:` 配置项)| 生产环境,Model 文件统一放在一个目录下 |
323
+
324
+ #### 方式一:手动注册
325
+
317
326
  ```javascript
318
327
  const MonSQLize = require('monsqlize');
319
328
  const { Model } = MonSQLize;
320
329
 
321
- const msq = new MonSQLize({
322
- type: 'mongodb',
323
- databaseName: 'mydb',
324
- config: { uri: 'mongodb://localhost:27017' },
325
- cache: { enabled: true },
326
- models: './models' // 🆕 v1.0.7: 自动加载 Model 文件
327
- });
328
-
329
- await msq.connect(); // 自动加载 models/*.model.js
330
-
331
- // 1. 定义 Model(带 Schema 验证、Relations 和 Hooks)
330
+ // 1. 先在 connect() 之前调用 Model.define() 注册所有 Model
332
331
  Model.define('users', {
333
- // 🔴 Schema 验证(默认启用,v1.0.7+,基于 schema-dsl 库)
334
332
  schema: (dsl) => dsl({
335
- username: 'string:3-32!', // 必需,3-32 字符
336
- email: 'email!', // 必需,邮箱格式
337
- password: 'string:6-!', // 必需,至少 6 字符
338
- age: 'number:0-120', // 可选,0-120 范围
339
- role: 'string?' // 可选字符串
333
+ username: 'string:3-32!',
334
+ email: 'email!',
335
+ password: 'string:6-!',
336
+ age: 'number:0-120'
340
337
  }),
341
-
342
- // Relations(关联查询)
343
338
  relations: {
344
- posts: { // 用户的文章
345
- from: 'posts',
346
- localField: '_id',
347
- foreignField: 'userId',
348
- single: false
349
- }
339
+ posts: { from: 'posts', localField: '_id', foreignField: 'userId', single: false }
350
340
  },
351
-
352
- // Hooks(生命周期钩子)
353
341
  hooks: (model) => ({
354
- insert: {
355
- before: async (ctx, doc) => {
356
- doc.createdAt = new Date(); // 自动添加时间戳
357
- return doc;
358
- }
359
- }
342
+ insert: { before: async (ctx, doc) => { doc.createdAt = new Date(); return doc; } }
360
343
  }),
361
-
362
- // 自定义方法
363
344
  methods: (model) => ({
364
- instance: {
365
- // 文档方法(注入到查询结果)
366
- checkPassword(password) {
367
- return this.password === password;
368
- }
369
- },
370
- static: {
371
- // Model 方法
372
- async findByUsername(username) {
373
- return await model.findOne({ username });
374
- }
375
- }
345
+ instance: { checkPassword(password) { return this.password === password; } },
346
+ static: { async findByUsername(username) { return await model.findOne({ username }); } }
376
347
  })
377
348
  });
378
349
 
379
350
  Model.define('posts', {
380
- schema: (dsl) => dsl({
381
- title: 'string:1-200!',
382
- content: 'string!',
383
- userId: 'string!'
384
- })
351
+ schema: (dsl) => dsl({ title: 'string:1-200!', content: 'string!', userId: 'string!' })
385
352
  });
386
353
 
387
- // 2. 使用 Model
354
+ // 2. 创建实例并连接
355
+ const msq = new MonSQLize({
356
+ type: 'mongodb',
357
+ databaseName: 'mydb',
358
+ config: { uri: 'mongodb://localhost:27017' },
359
+ cache: { enabled: true }
360
+ });
361
+ await msq.connect();
362
+
363
+ // 3. 获取 Model 并使用
388
364
  const User = msq.model('users');
365
+ ```
366
+
367
+ #### 方式二:自动加载(推荐用于生产环境)
368
+
369
+ 将每个 Model 单独放在一个文件里,`connect()` 时自动扫描目录加载,无需手动 `Model.define()`:
370
+
371
+ ```javascript
372
+ // app.js
373
+ const path = require('path');
374
+
375
+ const msq = new MonSQLize({
376
+ type: 'mongodb',
377
+ databaseName: 'mydb',
378
+ config: { uri: 'mongodb://localhost:27017' },
379
+ // 推荐用绝对路径,避免受 process.cwd() 影响
380
+ models: path.join(__dirname, 'models')
381
+ // 或完整配置:
382
+ // models: { path: path.join(__dirname, 'models'), pattern: '*.model.js', recursive: true }
383
+ });
384
+
385
+ await msq.connect(); // ← 自动扫描 models/*.model.{js,ts,mjs,cjs}
386
+
387
+ const User = msq.model('users'); // 直接使用,无需 Model.define()
388
+ ```
389
+
390
+ > 相对路径(如 `'./models'`)以 `process.cwd()` 为基准,即 Node.js 进程的启动目录。为避免歧义,推荐始终使用 `path.join(__dirname, 'models')` 这样的绝对路径。
391
+
392
+ ```javascript
393
+ // models/user.model.js ← 每个 Model 独立一个文件
394
+ module.exports = {
395
+ name: 'users', // 集合名称(必需)
396
+ schema: (dsl) => dsl({
397
+ username: 'string:3-32!',
398
+ email: 'email!'
399
+ }),
400
+ methods: (model) => ({
401
+ static: {
402
+ async findByUsername(username) { return await model.findOne({ username }); }
403
+ }
404
+ })
405
+ };
406
+ ```
407
+
408
+ > 详细说明(完整配置项、文件格式、错误处理)见 [docs/model.md — Model 自动加载](./docs/model.md#model-自动加载v107)
409
+
410
+ #### 两种方式共同的后续操作
411
+
412
+ ```javascript
389
413
 
390
414
  // ✅ Schema 验证自动生效
391
415
  try {
@@ -432,6 +456,35 @@ await User.insertOne(doc, { skipValidation: true });
432
456
  - ✅ **Relations** - 定义表关系(hasOne/hasMany/belongsTo)
433
457
  - ✅ **自定义方法** - instance 方法注入到文档,static 方法挂载到 Model
434
458
  - ✅ **自动缓存** - Populate 查询结果也会缓存
459
+ - ✅ **数据源绑定** - `connection: { pool?, database? }` 绑定指定连接池和/或数据库(v1.2.2+)
460
+
461
+ **数据源绑定示例(v1.2.2+)**:
462
+
463
+ ```js
464
+ // 在多连接池场景中,将 Model 绑定到指定的连接池 + 数据库
465
+ const msq = new MonSQLize({
466
+ uri: 'mongodb://localhost:27017',
467
+ databaseName: 'main_db',
468
+ pools: [{ name: 'analytics', uri: 'mongodb://analytics-host:27017' }]
469
+ });
470
+
471
+ // 绑定到不同数据库(使用默认连接池)
472
+ Model.define('AuditLog', {
473
+ schema: (dsl) => dsl({ action: 'string!', userId: 'string!' }),
474
+ connection: { database: 'audit_db' }
475
+ });
476
+
477
+ // 绑定到不同连接池 + 不同数据库
478
+ Model.define('AnalyticsReport', {
479
+ schema: (dsl) => dsl({ reportId: 'string!', data: 'object' }),
480
+ connection: { pool: 'analytics', database: 'reports_db' }
481
+ });
482
+
483
+ // 调用时自动路由,无需手动切换
484
+ const AuditLogModel = msq.model('AuditLog'); // → audit_db(默认池)
485
+ const ReportModel = msq.model('AnalyticsReport'); // → reports_db(analytics 池)
486
+ const UserModel = msq.model('users'); // → main_db(原逻辑,向后兼容)
487
+ ```
435
488
 
436
489
  📖 **详细文档**:[Model 层完整指南](./docs/model.md) | [Populate API](./docs/populate.md) | [Hooks API](./docs/hooks.md) | [Schema 验证](./docs/model.md#schema-验证)
437
490
 
@@ -1412,27 +1465,27 @@ import type { Collection, MonSQLizeConfig } from 'monsqlize';
1412
1465
  ### 📦 MongoDB 原生功能
1413
1466
 
1414
1467
  ✅ **CRUD 操作**
1415
- - find / findOne
1416
- - insertOne / insertMany
1417
- - updateOne / updateMany ⭐ (支持聚合管道 v1.0.8+)
1418
- - deleteOne / deleteMany
1419
- - replaceOne
1420
- - findOneAndUpdate
1421
- - findOneAndReplace
1422
- - findOneAndDelete
1468
+ - [find](./docs/find.md) / [findOne](./docs/findOne.md)
1469
+ - [insertOne](./docs/insert-one.md) / [insertMany](./docs/insert-many.md)
1470
+ - [updateOne](./docs/update-one.md) / [updateMany](./docs/update-many.md) ⭐ (支持聚合管道 v1.0.8+)
1471
+ - [deleteOne](./docs/delete-one.md) / [deleteMany](./docs/delete-many.md)
1472
+ - [replaceOne](./docs/replace-one.md)
1473
+ - [findOneAndUpdate](./docs/find-one-and-update.md)
1474
+ - [findOneAndReplace](./docs/find-one-and-replace.md)
1475
+ - [findOneAndDelete](./docs/find-one-and-delete.md)
1423
1476
 
1424
1477
  ✅ **聚合 & 查询**
1425
- - aggregate
1426
- - count / distinct
1427
- - watch (Change Streams)
1428
- - explain
1478
+ - [aggregate](./docs/aggregate.md)
1479
+ - [count](./docs/count.md) / [distinct](./docs/distinct.md)
1480
+ - [watch (Change Streams)](./docs/watch.md)
1481
+ - [explain](./docs/explain.md)
1429
1482
 
1430
1483
  ✅ **索引管理**
1431
1484
  - createIndex / createIndexes
1432
1485
  - listIndexes
1433
1486
  - dropIndex / dropIndexes
1434
1487
 
1435
- **事务支持**
1488
+ **[事务支持](./docs/transaction.md)**
1436
1489
  - withTransaction
1437
1490
  - startTransaction
1438
1491
 
@@ -1441,44 +1494,44 @@ import type { Collection, MonSQLizeConfig } from 'monsqlize';
1441
1494
 
1442
1495
  ### 🚀 增强功能
1443
1496
 
1444
- **企业级多连接池** (v1.0.8+)
1497
+ **[企业级多连接池](./docs/multi-pool.md)** (v1.0.8+)
1445
1498
  - ConnectionPoolManager
1446
1499
  - 5种智能选择策略
1447
1500
  - 实时健康检查
1448
1501
  - 自动故障转移
1449
1502
  - 完整统计收集
1450
1503
 
1451
- ✅ **Saga 分布式事务** (v1.1.0 计划)
1504
+ ✅ **[Saga 分布式事务](./docs/saga-transaction.md)** (v1.1.0 计划)
1452
1505
  - 跨服务事务(设计完成)
1453
1506
  - 自动补偿机制(设计完成)
1454
1507
  - 状态跟踪(设计完成)
1455
1508
  - 超时和重试(设计完成)
1456
1509
 
1457
- **智能缓存**
1510
+ **[智能缓存](./docs/cache.md)**
1458
1511
  - TTL 过期策略
1459
1512
  - LRU 淘汰策略
1460
1513
  - 自动失效机制
1461
1514
  - 并发去重
1462
- - 多层缓存 (内存+Redis)
1515
+ - [多层缓存 (内存+Redis)](./docs/cache-implementation.md)
1463
1516
 
1464
1517
  ✅ **便利方法**
1465
- - findOneById
1466
- - findByIds
1467
- - upsertOne
1468
- - incrementOne
1469
- - findAndCount
1518
+ - [findOneById](./docs/find-one-by-id.md)
1519
+ - [findByIds](./docs/find-by-ids.md)
1520
+ - [upsertOne](./docs/upsert-one.md)
1521
+ - [incrementOne](./docs/increment-one.md)
1522
+ - [findAndCount](./docs/find-and-count.md)
1470
1523
 
1471
1524
  ✅ **性能优化**
1472
- - insertBatch - 批量插入优化
1473
- - deleteBatch - 批量删除(流式+进度监控)
1474
- - updateBatch - 批量更新(流式+进度监控)
1525
+ - [insertBatch](./docs/insertBatch.md) - 批量插入优化
1526
+ - [deleteBatch](./docs/deleteBatch.md) - 批量删除(流式+进度监控)
1527
+ - [updateBatch](./docs/updateBatch.md) - 批量更新(流式+进度监控)
1475
1528
  - 只读事务优化
1476
- - Count 队列控制
1529
+ - [Count 队列控制](./docs/count-queue.md)
1477
1530
  - 连接池管理
1478
1531
 
1479
- **分布式支持**
1532
+ **[分布式支持](./docs/distributed-deployment.md)**
1480
1533
  - Redis 广播缓存失效
1481
- - 分布式锁
1534
+ - [分布式锁](./docs/business-lock.md)
1482
1535
  - 多实例一致性
1483
1536
 
1484
1537
  </td>
@@ -1487,28 +1540,28 @@ import type { Collection, MonSQLizeConfig } from 'monsqlize';
1487
1540
  ### 🛠️ 企业级特性
1488
1541
 
1489
1542
  ✅ **运维监控**
1490
- - 慢查询日志(支持持久化存储)🆕
1543
+ - [慢查询日志](./docs/slow-query-log.md)(支持持久化存储)🆕
1491
1544
  - 性能指标统计
1492
1545
  - 健康检查
1493
1546
  - 缓存命中率监控
1494
1547
 
1495
- **深度分页**
1548
+ **[深度分页](./docs/findPage.md)**
1496
1549
  - 游标分页
1497
1550
  - 异步总数统计
1498
- - 书签管理
1551
+ - [书签管理](./docs/bookmarks.md)
1499
1552
  - 跳页优化
1500
1553
 
1501
1554
  ✅ **数据库管理**
1502
1555
  - 跨库访问
1503
- - Schema 验证
1504
- - 集合管理
1556
+ - [Schema 验证](./docs/model.md)
1557
+ - [集合管理](./docs/collection-management.md)
1505
1558
  - 数据库命令
1506
1559
 
1507
1560
  ✅ **开发体验**
1508
1561
  - TypeScript 支持
1509
- - 链式调用 API ⭐
1562
+ - [链式调用 API](./docs/chaining-api.md)
1510
1563
  - ESM/CommonJS 双模式
1511
- - ObjectId 自动转换 ⭐
1564
+ - [ObjectId 自动转换](./docs/objectid-auto-convert.md)
1512
1565
  - 77% 测试覆盖率
1513
1566
 
1514
1567
  </td>
package/index.d.ts CHANGED
@@ -178,6 +178,7 @@ declare module 'monsqlize' {
178
178
  export import DefaultValue = Model.DefaultValue;
179
179
  export import HookContext = Model.HookContext;
180
180
  export import ValidationResult = Model.ValidationResult;
181
+ export import ModelConnection = Model.ModelConnection;
181
182
  export import ModelDefinition = Model.ModelDefinition;
182
183
  export import RelationConfig = Model.RelationConfig;
183
184
  export import PopulateConfig = Model.PopulateConfig;
package/lib/index.js CHANGED
@@ -737,8 +737,18 @@ module.exports = class {
737
737
  // 获取 Model 定义
738
738
  const modelDef = Model.get(collectionName);
739
739
 
740
- // 获取 collection 实例
741
- const collection = this.dbInstance.collection(collectionName);
740
+ // [v1.2.3 patch] 实际 MongoDB 集合名可能不同于注册 key
741
+ // 优先读 definition.collection > definition.name > key(fallback,向后兼容)
742
+ const actualCollectionName =
743
+ modelDef.definition.collection ||
744
+ modelDef.definition.name ||
745
+ collectionName;
746
+
747
+ // 获取 collection 实例(v1.2.2+ 支持 connection 路由)
748
+ const connection = modelDef.definition.connection;
749
+ const collection = (connection && (connection.pool || connection.database))
750
+ ? this._resolveModelCollection(actualCollectionName, connection)
751
+ : this.dbInstance.collection(actualCollectionName);
742
752
 
743
753
  // 创建 ModelInstance 并缓存
744
754
  const instance = new Model.ModelInstance(collection, modelDef.definition, this);
@@ -749,6 +759,55 @@ module.exports = class {
749
759
  return instance;
750
760
  }
751
761
 
762
+ /**
763
+ * 解析 Model 绑定的 collection(内部方法)
764
+ *
765
+ * 根据 Model 定义中的 connection 配置,将请求路由到正确的连接池和数据库。
766
+ *
767
+ * 四种组合:
768
+ * 1. pool + database → 指定池、指定数据库
769
+ * 2. pool 只配置 → 指定池、实例默认 databaseName
770
+ * 3. database 只配置 → 默认连接池、指定数据库
771
+ * 4. 均未配置 → 原逻辑(此方法不会被调用)
772
+ *
773
+ * @private
774
+ * @param {string} collectionName - 集合名称
775
+ * @param {{ pool?: string, database?: string }} connection - Model 的 connection 配置
776
+ * @returns {Object} monSQLize 包装 collection 对象
777
+ * @since v1.2.2
778
+ */
779
+ _resolveModelCollection(collectionName, connection) {
780
+ const poolName = connection.pool;
781
+ const dbName = connection.database || this.databaseName;
782
+
783
+ if (poolName) {
784
+ if (!this._poolManager) {
785
+ const err = new Error(
786
+ `Model '${collectionName}' requires pool '${poolName}' but no pools are configured. ` +
787
+ `Add 'pools' to MonSQLize constructor options.`
788
+ );
789
+ err.code = 'NO_POOL_MANAGER';
790
+ throw err;
791
+ }
792
+
793
+ const client = this._poolManager._getPool(poolName);
794
+ if (!client) {
795
+ const availablePools = this._poolManager.getPoolNames().join(', ');
796
+ const err = new Error(
797
+ `Pool '${poolName}' not found. Available pools: [${availablePools}]`
798
+ );
799
+ err.code = 'POOL_NOT_FOUND';
800
+ throw err;
801
+ }
802
+
803
+ // 指定池 + 数据库:通过 adapter 的 collectionFromClient 复用包装逻辑
804
+ return this._adapter.collectionFromClient(client, dbName, collectionName);
805
+ }
806
+
807
+ // 只切换数据库,用默认连接
808
+ return this.dbInstance.db(dbName).collection(collectionName);
809
+ }
810
+
752
811
  /**
753
812
  * 获取集合实例(代理方法)
754
813
  *
@@ -160,6 +160,11 @@ class Model {
160
160
  this._validateOptions(definition.options);
161
161
  }
162
162
 
163
+ // ========== 验证 connection 配置(v1.2.2+)==========
164
+ if (definition.connection) {
165
+ this._validateConnection(definition.connection);
166
+ }
167
+
163
168
  // ========== 解析 timestamps 配置 ==========
164
169
  const timestampsConfig = this._parseTimestampsConfig(
165
170
  definition.options?.timestamps,
@@ -222,6 +227,37 @@ class Model {
222
227
  }
223
228
  }
224
229
 
230
+ /**
231
+ * 验证 connection 配置
232
+ *
233
+ * @private
234
+ * @param {Object} connection - connection 配置对象
235
+ * @throws {Error} 配置不合法时抛出错误
236
+ *
237
+ * @since v1.2.2
238
+ */
239
+ static _validateConnection(connection) {
240
+ if (!connection || typeof connection !== 'object') {
241
+ return;
242
+ }
243
+
244
+ if (connection.pool !== undefined) {
245
+ if (typeof connection.pool !== 'string' || connection.pool.trim() === '') {
246
+ const err = new Error('connection.pool must be a non-empty string');
247
+ err.code = 'INVALID_MODEL_DEFINITION';
248
+ throw err;
249
+ }
250
+ }
251
+
252
+ if (connection.database !== undefined) {
253
+ if (typeof connection.database !== 'string' || connection.database.trim() === '') {
254
+ const err = new Error('connection.database must be a non-empty string');
255
+ err.code = 'INVALID_MODEL_DEFINITION';
256
+ throw err;
257
+ }
258
+ }
259
+ }
260
+
225
261
  /**
226
262
  * 验证 options 配置
227
263
  * @private
@@ -454,8 +490,12 @@ class Model {
454
490
  * @private
455
491
  */
456
492
  static _clear() {
493
+ // 将所有已注册名标记为需要缓存失效,让 msq.model() 重建 ModelInstance
494
+ for (const name of this._registry.keys()) {
495
+ this._redefinedNames.add(name);
496
+ }
457
497
  this._registry.clear();
458
- this._redefinedNames.clear();
498
+ // 注意:不清除 _redefinedNames,确保 msq 实例缓存能感知本次 clear
459
499
  }
460
500
  }
461
501
 
@@ -336,6 +336,31 @@ module.exports = class {
336
336
  };
337
337
  }
338
338
 
339
+ /**
340
+ * 从指定 MongoClient 创建包装 collection(用于多连接池 Model 绑定场景)
341
+ *
342
+ * 当 Model 定义了 `connection.pool` 时,`msq.model()` 会调用此方法,
343
+ * 将指定连接池的 MongoClient 传入,复用现有 collection() 的完整包装逻辑
344
+ * (runner、缓存、慢查询等),避免重复实现。
345
+ *
346
+ * 线程安全说明:Node.js 单线程,临时替换 this.client 的同步操作无竞态风险。
347
+ *
348
+ * @param {import('mongodb').MongoClient} client - 指定连接池的 MongoClient 实例
349
+ * @param {string} databaseName - 数据库名称
350
+ * @param {string} collectionName - 集合名称
351
+ * @returns {Object} monSQLize 包装 collection 对象
352
+ * @since v1.2.2
353
+ */
354
+ collectionFromClient(client, databaseName, collectionName) {
355
+ const originalClient = this.client;
356
+ this.client = client;
357
+ try {
358
+ return this.collection(databaseName, collectionName);
359
+ } finally {
360
+ this.client = originalClient;
361
+ }
362
+ }
363
+
339
364
  /**
340
365
  * 关闭连接并释放资源
341
366
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monsqlize",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "A lightweight MongoDB ORM with multi-level caching, transaction support, distributed features, Saga distributed transactions, unified expression system with 122 operators, and universal function caching (100% MongoDB support)",
5
5
  "main": "lib/index.js",
6
6
  "module": "index.mjs",
@@ -114,7 +114,7 @@
114
114
  },
115
115
  "dependencies": {
116
116
  "async-lock": "^1.4.1",
117
- "mongodb": "^6.17.0",
117
+ "mongodb": "^6.21.0",
118
118
  "schema-dsl": "^1.2.4",
119
119
  "ssh2": "^1.17.0"
120
120
  }
@@ -106,5 +106,47 @@ export interface ModelDefinition<T = any> {
106
106
  * }
107
107
  */
108
108
  statics?: Record<string, (...args: any[]) => any>;
109
+
110
+ /**
111
+ * 数据源绑定配置(v1.2.2+)
112
+ *
113
+ * 声明此 Model 使用哪个连接池和/或数据库。
114
+ * 不配置时行为与 v1.2.1 完全相同(向后兼容)。
115
+ *
116
+ * @example
117
+ * // 绑定到指定连接池 + 数据库
118
+ * connection: { pool: 'analytics', database: 'reports_db' }
119
+ *
120
+ * @example
121
+ * // 只切换数据库(使用默认连接池)
122
+ * connection: { database: 'logs_db' }
123
+ *
124
+ * @since v1.2.2
125
+ */
126
+ connection?: ModelConnection;
127
+ }
128
+
129
+ /**
130
+ * Model 数据源绑定配置
131
+ *
132
+ * 声明 Model 使用哪个连接池(pool)和/或数据库(database)。
133
+ * 两个字段均为可选:
134
+ * - 只指定 pool → 使用该池 + 实例初始化时的 databaseName
135
+ * - 只指定 database → 使用默认连接池 + 指定数据库
136
+ * - 两者都指定 → 使用指定池 + 指定数据库
137
+ * - 均不指定 → 与原来完全相同(向后兼容)
138
+ *
139
+ * @since v1.2.2
140
+ */
141
+ export interface ModelConnection {
142
+ /**
143
+ * 连接池名称,须与 MonSQLize 构造函数 `pools[].name` 对应
144
+ */
145
+ pool?: string;
146
+
147
+ /**
148
+ * 数据库名称,不指定时使用实例初始化时的 `databaseName`
149
+ */
150
+ database?: string;
109
151
  }
110
152