monsqlize 1.1.8 → 1.1.9
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 +2 -1
- package/lib/connect.js +99 -99
- package/lib/multi-level-cache.js +39 -8
- package/lib/redis-cache-adapter.js +29 -0
- package/package.json +121 -121
- package/types/collection.ts +357 -357
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 变更日志 (CHANGELOG)
|
|
2
2
|
|
|
3
3
|
> **说明**: 版本概览摘要,详细变更见 [changelogs/](./changelogs/) 目录
|
|
4
|
-
> **最后更新**: 2026-
|
|
4
|
+
> **最后更新**: 2026-04-02
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
| 版本 | 日期 | 变更摘要 | 详细 |
|
|
11
11
|
|------|------|---------|------|
|
|
12
|
+
| [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) |
|
|
12
13
|
| [v1.1.8](./changelogs/v1.1.8.md) | 2026-03-16 | 🆕 **新功能**:Model 热重载支持(`undefine()` + `redefine()` + `_loadModels` reload 模式)+ 22个测试 (100%通过) | [查看](./changelogs/v1.1.8.md) |
|
|
13
14
|
| [v1.1.6](./changelogs/v1.1.6.md) | 2026-02-11 | 🎉 **重大功能**:精准缓存失效机制 + 🚨 upsert 缓存失效 Bug 修复 + 36个测试 (100%通过) | [查看](./changelogs/v1.1.6.md) |
|
|
14
15
|
| [v1.1.4](./changelogs/v1.1.4.md) | 2026-02-09 | 🎉 重大功能:通用函数缓存 - 52个测试 (100%通过) + 多层缓存 delPattern 修复 | [查看](./changelogs/v1.1.4.md) |
|
package/lib/connect.js
CHANGED
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 数据库连接管理器
|
|
3
|
-
* 统一管理各种数据库的连接创建和实例化逻辑
|
|
4
|
-
*/
|
|
5
|
-
const Mongo = require("./mongodb");
|
|
6
|
-
|
|
7
|
-
module.exports = class ConnectionManager {
|
|
8
|
-
/**
|
|
9
|
-
* 支持的数据库类型映射
|
|
10
|
-
*/
|
|
11
|
-
static get SUPPORTED_DATABASES() {
|
|
12
|
-
return {
|
|
13
|
-
mongodb: Mongo,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 创建数据库实例
|
|
19
|
-
* @param {string} type - 数据库类型
|
|
20
|
-
* @param {string} databaseName - 数据库名称
|
|
21
|
-
* @param {Object} cache - 缓存实例(内存缓存)
|
|
22
|
-
* @param {Object} logger - 日志记录器
|
|
23
|
-
* @param {Object} [defaults] - 统一默认配置(如 maxTimeMS、namespace)
|
|
24
|
-
* @returns {Object} 数据库实例
|
|
25
|
-
* @throws {Error} 当数据库类型不支持或未实现时抛出错误
|
|
26
|
-
*/
|
|
27
|
-
static createInstance(type, databaseName, cache, logger, defaults) {
|
|
28
|
-
const SUPPORTED_DATABASES = this.SUPPORTED_DATABASES;
|
|
29
|
-
// 验证数据库类型是否支持
|
|
30
|
-
if (!(type in SUPPORTED_DATABASES)) {
|
|
31
|
-
const supportedTypes = Object.keys(SUPPORTED_DATABASES).join(", ");
|
|
32
|
-
throw new Error(
|
|
33
|
-
`Invalid database type: ${type}. Supported types are: ${supportedTypes}`,
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 检查是否已实现
|
|
38
|
-
if (SUPPORTED_DATABASES[type] === null) {
|
|
39
|
-
throw new Error(`${type} support not implemented yet`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 获取对应的数据库类
|
|
43
|
-
const DatabaseClass = SUPPORTED_DATABASES[type];
|
|
44
|
-
|
|
45
|
-
// 创建并返回实例
|
|
46
|
-
return new DatabaseClass(type, databaseName, cache, logger, defaults);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 连接数据库
|
|
51
|
-
* @param {string} type - 数据库类型
|
|
52
|
-
* @param {string} databaseName - 数据库名称
|
|
53
|
-
* @param {Object} config - 数据库连接配置
|
|
54
|
-
* @param {Object} cache - 缓存实例
|
|
55
|
-
* @param {Object} logger - 日志记录器
|
|
56
|
-
* @param {Object} [defaults] - 统一默认配置(如 maxTimeMS、namespace)
|
|
57
|
-
* @param {Object} [poolManager] - 多连接池管理器(v1.0.8+)
|
|
58
|
-
* @returns {{accessor: Function, instance: Object}} 访问器与底层适配器实例
|
|
59
|
-
* @throws {Error} 连接失败时抛出错误
|
|
60
|
-
*/
|
|
61
|
-
static async connect(
|
|
62
|
-
type,
|
|
63
|
-
databaseName,
|
|
64
|
-
config,
|
|
65
|
-
cache,
|
|
66
|
-
logger,
|
|
67
|
-
defaults,
|
|
68
|
-
poolManager,
|
|
69
|
-
) {
|
|
70
|
-
// 创建数据库实例
|
|
71
|
-
const instance = this.createInstance(
|
|
72
|
-
type,
|
|
73
|
-
databaseName,
|
|
74
|
-
cache,
|
|
75
|
-
logger,
|
|
76
|
-
defaults,
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
// 🆕 v1.0.8: 传递 poolManager 给实例
|
|
80
|
-
if (poolManager) {
|
|
81
|
-
instance.poolManager = poolManager;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// 建立连接
|
|
85
|
-
await instance.connect(config);
|
|
86
|
-
|
|
87
|
-
// ---------- 构建访问器 ----------
|
|
88
|
-
const collection = (collectionName) =>
|
|
89
|
-
instance.collection(databaseName, collectionName);
|
|
90
|
-
const db = (databaseName) => {
|
|
91
|
-
return {
|
|
92
|
-
collection: (collectionName) =>
|
|
93
|
-
instance.collection(databaseName, collectionName),
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
return { collection, db, use: db, instance };
|
|
98
|
-
}
|
|
99
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* 数据库连接管理器
|
|
3
|
+
* 统一管理各种数据库的连接创建和实例化逻辑
|
|
4
|
+
*/
|
|
5
|
+
const Mongo = require("./mongodb");
|
|
6
|
+
|
|
7
|
+
module.exports = class ConnectionManager {
|
|
8
|
+
/**
|
|
9
|
+
* 支持的数据库类型映射
|
|
10
|
+
*/
|
|
11
|
+
static get SUPPORTED_DATABASES() {
|
|
12
|
+
return {
|
|
13
|
+
mongodb: Mongo,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 创建数据库实例
|
|
19
|
+
* @param {string} type - 数据库类型
|
|
20
|
+
* @param {string} databaseName - 数据库名称
|
|
21
|
+
* @param {Object} cache - 缓存实例(内存缓存)
|
|
22
|
+
* @param {Object} logger - 日志记录器
|
|
23
|
+
* @param {Object} [defaults] - 统一默认配置(如 maxTimeMS、namespace)
|
|
24
|
+
* @returns {Object} 数据库实例
|
|
25
|
+
* @throws {Error} 当数据库类型不支持或未实现时抛出错误
|
|
26
|
+
*/
|
|
27
|
+
static createInstance(type, databaseName, cache, logger, defaults) {
|
|
28
|
+
const SUPPORTED_DATABASES = this.SUPPORTED_DATABASES;
|
|
29
|
+
// 验证数据库类型是否支持
|
|
30
|
+
if (!(type in SUPPORTED_DATABASES)) {
|
|
31
|
+
const supportedTypes = Object.keys(SUPPORTED_DATABASES).join(", ");
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Invalid database type: ${type}. Supported types are: ${supportedTypes}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 检查是否已实现
|
|
38
|
+
if (SUPPORTED_DATABASES[type] === null) {
|
|
39
|
+
throw new Error(`${type} support not implemented yet`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 获取对应的数据库类
|
|
43
|
+
const DatabaseClass = SUPPORTED_DATABASES[type];
|
|
44
|
+
|
|
45
|
+
// 创建并返回实例
|
|
46
|
+
return new DatabaseClass(type, databaseName, cache, logger, defaults);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 连接数据库
|
|
51
|
+
* @param {string} type - 数据库类型
|
|
52
|
+
* @param {string} databaseName - 数据库名称
|
|
53
|
+
* @param {Object} config - 数据库连接配置
|
|
54
|
+
* @param {Object} cache - 缓存实例
|
|
55
|
+
* @param {Object} logger - 日志记录器
|
|
56
|
+
* @param {Object} [defaults] - 统一默认配置(如 maxTimeMS、namespace)
|
|
57
|
+
* @param {Object} [poolManager] - 多连接池管理器(v1.0.8+)
|
|
58
|
+
* @returns {{accessor: Function, instance: Object}} 访问器与底层适配器实例
|
|
59
|
+
* @throws {Error} 连接失败时抛出错误
|
|
60
|
+
*/
|
|
61
|
+
static async connect(
|
|
62
|
+
type,
|
|
63
|
+
databaseName,
|
|
64
|
+
config,
|
|
65
|
+
cache,
|
|
66
|
+
logger,
|
|
67
|
+
defaults,
|
|
68
|
+
poolManager,
|
|
69
|
+
) {
|
|
70
|
+
// 创建数据库实例
|
|
71
|
+
const instance = this.createInstance(
|
|
72
|
+
type,
|
|
73
|
+
databaseName,
|
|
74
|
+
cache,
|
|
75
|
+
logger,
|
|
76
|
+
defaults,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// 🆕 v1.0.8: 传递 poolManager 给实例
|
|
80
|
+
if (poolManager) {
|
|
81
|
+
instance.poolManager = poolManager;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 建立连接
|
|
85
|
+
await instance.connect(config);
|
|
86
|
+
|
|
87
|
+
// ---------- 构建访问器 ----------
|
|
88
|
+
const collection = (collectionName) =>
|
|
89
|
+
instance.collection(databaseName, collectionName);
|
|
90
|
+
const db = (databaseName) => {
|
|
91
|
+
return {
|
|
92
|
+
collection: (collectionName) =>
|
|
93
|
+
instance.collection(databaseName, collectionName),
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return { collection, db, use: db, instance };
|
|
98
|
+
}
|
|
99
|
+
};
|
package/lib/multi-level-cache.js
CHANGED
|
@@ -16,8 +16,12 @@ class MultiLevelCache {
|
|
|
16
16
|
* @param {Object} [options.policy]
|
|
17
17
|
* @param {'both'|'local-first-async-remote'} [options.policy.writePolicy='both']
|
|
18
18
|
* @param {boolean} [options.policy.backfillLocalOnRemoteHit=true]
|
|
19
|
+
* @param {number} [options.policy.backfillLocalTTL=0] - 回填 L1 时使用的兜底 TTL(毫秒);
|
|
20
|
+
* 当 remote 支持 getWithTTL 时优先使用 L2 剩余 TTL,否则降级到此值;
|
|
21
|
+
* 0 = 不设 TTL(永不过期,向后兼容)。建议生产环境配置合理值(如 60000)
|
|
19
22
|
* @param {number} [options.remoteTimeoutMs=50] - 远端单次操作超时
|
|
20
23
|
* @param {(msg:object)=>void} [options.publish] - 可选:失效广播发布器
|
|
24
|
+
* @since 1.1.9 backfillLocalTTL 支持
|
|
21
25
|
*/
|
|
22
26
|
constructor(options = {}) {
|
|
23
27
|
const { local, remote, policy = {}, remoteTimeoutMs = 50, publish } = options;
|
|
@@ -29,6 +33,8 @@ class MultiLevelCache {
|
|
|
29
33
|
this.policy = {
|
|
30
34
|
writePolicy: policy.writePolicy || 'both',
|
|
31
35
|
backfillLocalOnRemoteHit: policy.backfillLocalOnRemoteHit !== false,
|
|
36
|
+
// 🔧 v1.1.9 修复:新增回填 TTL 兜底配置,0 = 不设 TTL(向后兼容)
|
|
37
|
+
backfillLocalTTL: typeof policy.backfillLocalTTL === 'number' ? policy.backfillLocalTTL : 0,
|
|
32
38
|
};
|
|
33
39
|
this.remoteTimeoutMs = Number(remoteTimeoutMs) || 50;
|
|
34
40
|
this.publish = typeof publish === 'function' ? publish : null;
|
|
@@ -74,13 +80,30 @@ class MultiLevelCache {
|
|
|
74
80
|
const v = await this.local.get(key);
|
|
75
81
|
if (v !== undefined) return v;
|
|
76
82
|
try {
|
|
77
|
-
|
|
83
|
+
let r;
|
|
84
|
+
// 🔧 v1.1.9 修复:backfillTTL 优先取 L2 剩余 TTL(方案A),降级到 backfillLocalTTL(方案B)
|
|
85
|
+
let backfillTTL = this.policy.backfillLocalTTL;
|
|
86
|
+
|
|
87
|
+
if (this.remote && typeof this.remote.getWithTTL === 'function') {
|
|
88
|
+
// 方案A:remote 支持 getWithTTL,单次 RTT 同时获取值与剩余 TTL
|
|
89
|
+
const meta = await this._withTimeout(this.remote.getWithTTL(key));
|
|
90
|
+
if (meta !== undefined) {
|
|
91
|
+
r = meta.value;
|
|
92
|
+
if (meta.remainingTTL > 0) backfillTTL = meta.remainingTTL;
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
// 方案B:remote 不支持 getWithTTL,使用普通 get + backfillLocalTTL 兜底
|
|
96
|
+
r = await this._withTimeout(this.remote.get(key));
|
|
97
|
+
}
|
|
98
|
+
|
|
78
99
|
if (r !== undefined && this.policy.backfillLocalOnRemoteHit) {
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
|
|
100
|
+
// 🔧 v1.1.9 补充:backfillTTL=0 时跳过 null 回填,防止无配置用户触发永久驻留 Bug
|
|
101
|
+
// - backfillTTL>0:回填所有值(含 null),TTL 保护下能正常过期
|
|
102
|
+
// - backfillTTL=0 + null:跳过——无 TTL 保护的 null 永久驻留 = Bug 本身
|
|
103
|
+
// - backfillTTL=0 + 非 null:回填(保留原有永久缓存行为,向后兼容)
|
|
104
|
+
if (backfillTTL > 0 || r !== null) {
|
|
105
|
+
try { await this.local.set(key, r, backfillTTL); } catch(_) {}
|
|
106
|
+
}
|
|
84
107
|
}
|
|
85
108
|
return r;
|
|
86
109
|
} catch(_) {
|
|
@@ -128,8 +151,16 @@ class MultiLevelCache {
|
|
|
128
151
|
try {
|
|
129
152
|
const remoteRes = await this._withTimeout(this.remote.getMany(misses));
|
|
130
153
|
if (remoteRes && typeof remoteRes === 'object') {
|
|
131
|
-
//
|
|
132
|
-
|
|
154
|
+
// 🔧 v1.1.9 修复:传入 backfillLocalTTL,防止无 TTL 永久回填(含 null 值)
|
|
155
|
+
// 🔧 v1.1.9 补充:backfillLocalTTL=0 时过滤 null,防止无配置用户触发永久驻留 Bug
|
|
156
|
+
if (this.policy.backfillLocalOnRemoteHit) {
|
|
157
|
+
const backfillData = this.policy.backfillLocalTTL > 0
|
|
158
|
+
? remoteRes
|
|
159
|
+
: Object.fromEntries(Object.entries(remoteRes).filter(([, v]) => v !== null));
|
|
160
|
+
if (Object.keys(backfillData).length > 0) {
|
|
161
|
+
this.local.setMany(backfillData, this.policy.backfillLocalTTL).catch(() => {});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
133
164
|
for (const k of misses) { if (remoteRes[k] !== undefined) out[k] = remoteRes[k]; }
|
|
134
165
|
}
|
|
135
166
|
} catch(_) { /* 降级 */ }
|
|
@@ -60,6 +60,35 @@ function createRedisCacheAdapter(redisUrlOrInstance) {
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 获取单个缓存值及剩余 TTL(毫秒),供 MultiLevelCache L2→L1 回填时携带正确 TTL
|
|
65
|
+
* 使用 pipeline(GET + PTTL)单次 RTT,避免额外网络开销
|
|
66
|
+
* @param {string} key
|
|
67
|
+
* @returns {Promise<{value: any, remainingTTL: number}|undefined>}
|
|
68
|
+
* key 不存在返回 undefined;value 为 null 时表示缓存了空结果
|
|
69
|
+
* @since 1.1.9
|
|
70
|
+
*/
|
|
71
|
+
async getWithTTL(key) {
|
|
72
|
+
try {
|
|
73
|
+
const [[, rawVal], [, pttl]] = await redis.pipeline().get(key).pttl(key).exec();
|
|
74
|
+
// PTTL = -2 表示 key 不存在
|
|
75
|
+
if (pttl === -2) return undefined;
|
|
76
|
+
let value;
|
|
77
|
+
try {
|
|
78
|
+
value = JSON.parse(rawVal);
|
|
79
|
+
} catch (_) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
value,
|
|
84
|
+
// PTTL = -1 表示永不过期,映射为 0(与 backfillLocalTTL=0 语义一致)
|
|
85
|
+
remainingTTL: pttl > 0 ? pttl : 0,
|
|
86
|
+
};
|
|
87
|
+
} catch (_) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
|
|
63
92
|
/**
|
|
64
93
|
* 设置单个缓存值
|
|
65
94
|
* @param {string} key
|
package/package.json
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "monsqlize",
|
|
3
|
-
"version": "1.1.
|
|
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
|
-
"main": "lib/index.js",
|
|
6
|
-
"module": "index.mjs",
|
|
7
|
-
"type": "commonjs",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"require": "./lib/index.js",
|
|
11
|
-
"import": "./index.mjs",
|
|
12
|
-
"types": "./index.d.ts"
|
|
13
|
-
},
|
|
14
|
-
"./package.json": "./package.json"
|
|
15
|
-
},
|
|
16
|
-
"types": "./index.d.ts",
|
|
17
|
-
"files": [
|
|
18
|
-
"lib/",
|
|
19
|
-
"types/",
|
|
20
|
-
"index.d.ts",
|
|
21
|
-
"index.mjs",
|
|
22
|
-
"README.md",
|
|
23
|
-
"LICENSE",
|
|
24
|
-
"CHANGELOG.md"
|
|
25
|
-
],
|
|
26
|
-
"keywords": [
|
|
27
|
-
"mongodb",
|
|
28
|
-
"database",
|
|
29
|
-
"orm",
|
|
30
|
-
"cache",
|
|
31
|
-
"transaction",
|
|
32
|
-
"distributed",
|
|
33
|
-
"pagination",
|
|
34
|
-
"performance",
|
|
35
|
-
"mongodb-driver",
|
|
36
|
-
"nosql",
|
|
37
|
-
"query-builder",
|
|
38
|
-
"api"
|
|
39
|
-
],
|
|
40
|
-
"author": "vext.js Team",
|
|
41
|
-
"license": "MIT",
|
|
42
|
-
"repository": {
|
|
43
|
-
"type": "git",
|
|
44
|
-
"url": "https://github.com/vextjs/monSQLize.git"
|
|
45
|
-
},
|
|
46
|
-
"bugs": {
|
|
47
|
-
"url": "https://github.com/vextjs/monSQLize/issues"
|
|
48
|
-
},
|
|
49
|
-
"homepage": "https://github.com/vextjs/monSQLize#readme",
|
|
50
|
-
"engines": {
|
|
51
|
-
"node": ">=16.0.0"
|
|
52
|
-
},
|
|
53
|
-
"scripts": {
|
|
54
|
-
"test": "node test/run-tests.js",
|
|
55
|
-
"test:unit": "node test/run-tests.js",
|
|
56
|
-
"test:performance": "node test/performance/transaction-benchmark.js",
|
|
57
|
-
"test:coverage": "nyc --reporter=text --reporter=lcov node test/run-tests.js",
|
|
58
|
-
"coverage": "nyc --reporter=text --reporter=lcov --reporter=html node test/run-tests.js",
|
|
59
|
-
"benchmark": "node test/benchmark/run-benchmarks.js",
|
|
60
|
-
"test:compatibility": "node test/compatibility/run-node-test.js",
|
|
61
|
-
"test:compatibility:node": "node scripts/test-node-versions.js",
|
|
62
|
-
"test:compatibility:driver": "node scripts/test-driver-versions-simple.js",
|
|
63
|
-
"test:compatibility:driver:full": "node scripts/test-driver-versions-simple.js --drivers=4.17.2,5.9.2,6.17.0,7.0.0",
|
|
64
|
-
"test:compatibility:driver:quick": "node test/compatibility/run-driver-test.js",
|
|
65
|
-
"test:compatibility:server": "node scripts/test-server-versions.js --use-memory-server",
|
|
66
|
-
"test:compatibility:server:quick": "node test/compatibility/run-server-test.js",
|
|
67
|
-
"test:compatibility:server:docker": "node scripts/test-server-versions.js",
|
|
68
|
-
"lint": "eslint lib/ test/ --ext .js",
|
|
69
|
-
"lint:fix": "eslint lib/ test/ --ext .js --fix",
|
|
70
|
-
"type-check": "tsc",
|
|
71
|
-
"postpublish": "echo '✅ 发布成功!请创建 GitHub Release: https://github.com/vextjs/monSQLize/releases/new?tag=v'$npm_package_version"
|
|
72
|
-
},
|
|
73
|
-
"peerDependenciesMeta": {
|
|
74
|
-
"ioredis": {
|
|
75
|
-
"optional": true
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
"optionalDependencies": {
|
|
79
|
-
"ioredis": "^5.8.2"
|
|
80
|
-
},
|
|
81
|
-
"devDependencies": {
|
|
82
|
-
"@eslint/js": "^9.39.1",
|
|
83
|
-
"@types/node": "^25.0.1",
|
|
84
|
-
"benchmark": "^2.1.4",
|
|
85
|
-
"chai": "^6.2.1",
|
|
86
|
-
"eslint": "^9.39.1",
|
|
87
|
-
"mocha": "^11.7.5",
|
|
88
|
-
"mongodb-memory-server": "^10.1.2",
|
|
89
|
-
"nyc": "^15.1.0",
|
|
90
|
-
"sinon": "^21.0.0",
|
|
91
|
-
"tsd": "^0.33.0",
|
|
92
|
-
"typescript": "^5.9.3"
|
|
93
|
-
},
|
|
94
|
-
"nyc": {
|
|
95
|
-
"include": [
|
|
96
|
-
"lib/**/*.js"
|
|
97
|
-
],
|
|
98
|
-
"exclude": [
|
|
99
|
-
"test/**",
|
|
100
|
-
"examples/**",
|
|
101
|
-
"scripts/**",
|
|
102
|
-
"reports/**"
|
|
103
|
-
],
|
|
104
|
-
"reporter": [
|
|
105
|
-
"text",
|
|
106
|
-
"lcov",
|
|
107
|
-
"html"
|
|
108
|
-
],
|
|
109
|
-
"check-coverage": true,
|
|
110
|
-
"lines": 70,
|
|
111
|
-
"statements": 70,
|
|
112
|
-
"functions": 70,
|
|
113
|
-
"branches": 65
|
|
114
|
-
},
|
|
115
|
-
"dependencies": {
|
|
116
|
-
"async-lock": "^1.4.1",
|
|
117
|
-
"mongodb": "^6.17.0",
|
|
118
|
-
"schema-dsl": "^1.2.4",
|
|
119
|
-
"ssh2": "^1.17.0"
|
|
120
|
-
}
|
|
121
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "monsqlize",
|
|
3
|
+
"version": "1.1.9",
|
|
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
|
+
"main": "lib/index.js",
|
|
6
|
+
"module": "index.mjs",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./lib/index.js",
|
|
11
|
+
"import": "./index.mjs",
|
|
12
|
+
"types": "./index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"types": "./index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"lib/",
|
|
19
|
+
"types/",
|
|
20
|
+
"index.d.ts",
|
|
21
|
+
"index.mjs",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"CHANGELOG.md"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mongodb",
|
|
28
|
+
"database",
|
|
29
|
+
"orm",
|
|
30
|
+
"cache",
|
|
31
|
+
"transaction",
|
|
32
|
+
"distributed",
|
|
33
|
+
"pagination",
|
|
34
|
+
"performance",
|
|
35
|
+
"mongodb-driver",
|
|
36
|
+
"nosql",
|
|
37
|
+
"query-builder",
|
|
38
|
+
"api"
|
|
39
|
+
],
|
|
40
|
+
"author": "vext.js Team",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/vextjs/monSQLize.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/vextjs/monSQLize/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/vextjs/monSQLize#readme",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=16.0.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"test": "node test/run-tests.js",
|
|
55
|
+
"test:unit": "node test/run-tests.js",
|
|
56
|
+
"test:performance": "node test/performance/transaction-benchmark.js",
|
|
57
|
+
"test:coverage": "nyc --reporter=text --reporter=lcov node test/run-tests.js",
|
|
58
|
+
"coverage": "nyc --reporter=text --reporter=lcov --reporter=html node test/run-tests.js",
|
|
59
|
+
"benchmark": "node test/benchmark/run-benchmarks.js",
|
|
60
|
+
"test:compatibility": "node test/compatibility/run-node-test.js",
|
|
61
|
+
"test:compatibility:node": "node scripts/test-node-versions.js",
|
|
62
|
+
"test:compatibility:driver": "node scripts/test-driver-versions-simple.js",
|
|
63
|
+
"test:compatibility:driver:full": "node scripts/test-driver-versions-simple.js --drivers=4.17.2,5.9.2,6.17.0,7.0.0",
|
|
64
|
+
"test:compatibility:driver:quick": "node test/compatibility/run-driver-test.js",
|
|
65
|
+
"test:compatibility:server": "node scripts/test-server-versions.js --use-memory-server",
|
|
66
|
+
"test:compatibility:server:quick": "node test/compatibility/run-server-test.js",
|
|
67
|
+
"test:compatibility:server:docker": "node scripts/test-server-versions.js",
|
|
68
|
+
"lint": "eslint lib/ test/ --ext .js",
|
|
69
|
+
"lint:fix": "eslint lib/ test/ --ext .js --fix",
|
|
70
|
+
"type-check": "tsc",
|
|
71
|
+
"postpublish": "echo '✅ 发布成功!请创建 GitHub Release: https://github.com/vextjs/monSQLize/releases/new?tag=v'$npm_package_version"
|
|
72
|
+
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"ioredis": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"optionalDependencies": {
|
|
79
|
+
"ioredis": "^5.8.2"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@eslint/js": "^9.39.1",
|
|
83
|
+
"@types/node": "^25.0.1",
|
|
84
|
+
"benchmark": "^2.1.4",
|
|
85
|
+
"chai": "^6.2.1",
|
|
86
|
+
"eslint": "^9.39.1",
|
|
87
|
+
"mocha": "^11.7.5",
|
|
88
|
+
"mongodb-memory-server": "^10.1.2",
|
|
89
|
+
"nyc": "^15.1.0",
|
|
90
|
+
"sinon": "^21.0.0",
|
|
91
|
+
"tsd": "^0.33.0",
|
|
92
|
+
"typescript": "^5.9.3"
|
|
93
|
+
},
|
|
94
|
+
"nyc": {
|
|
95
|
+
"include": [
|
|
96
|
+
"lib/**/*.js"
|
|
97
|
+
],
|
|
98
|
+
"exclude": [
|
|
99
|
+
"test/**",
|
|
100
|
+
"examples/**",
|
|
101
|
+
"scripts/**",
|
|
102
|
+
"reports/**"
|
|
103
|
+
],
|
|
104
|
+
"reporter": [
|
|
105
|
+
"text",
|
|
106
|
+
"lcov",
|
|
107
|
+
"html"
|
|
108
|
+
],
|
|
109
|
+
"check-coverage": true,
|
|
110
|
+
"lines": 70,
|
|
111
|
+
"statements": 70,
|
|
112
|
+
"functions": 70,
|
|
113
|
+
"branches": 65
|
|
114
|
+
},
|
|
115
|
+
"dependencies": {
|
|
116
|
+
"async-lock": "^1.4.1",
|
|
117
|
+
"mongodb": "^6.17.0",
|
|
118
|
+
"schema-dsl": "^1.2.4",
|
|
119
|
+
"ssh2": "^1.17.0"
|
|
120
|
+
}
|
|
121
|
+
}
|
package/types/collection.ts
CHANGED
|
@@ -1,357 +1,357 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collection API 相关类型定义
|
|
3
|
-
* @module types/collection
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type {
|
|
7
|
-
FindOptions,
|
|
8
|
-
CountOptions,
|
|
9
|
-
AggregateOptions,
|
|
10
|
-
DistinctOptions,
|
|
11
|
-
} from "./query";
|
|
12
|
-
import type {
|
|
13
|
-
InsertOneSimplifiedOptions,
|
|
14
|
-
InsertOneOptions,
|
|
15
|
-
InsertOneResult,
|
|
16
|
-
InsertManySimplifiedOptions,
|
|
17
|
-
InsertManyOptions,
|
|
18
|
-
InsertManyResult,
|
|
19
|
-
} from "./write";
|
|
20
|
-
import type {
|
|
21
|
-
InsertBatchOptions,
|
|
22
|
-
InsertBatchResult,
|
|
23
|
-
UpdateBatchOptions,
|
|
24
|
-
UpdateBatchResult,
|
|
25
|
-
DeleteBatchOptions,
|
|
26
|
-
DeleteBatchResult,
|
|
27
|
-
} from "./batch";
|
|
28
|
-
import type {
|
|
29
|
-
FindPageOptions,
|
|
30
|
-
PageResult,
|
|
31
|
-
ResultWithMeta,
|
|
32
|
-
MetaOptions,
|
|
33
|
-
BookmarkKeyDims,
|
|
34
|
-
PrewarmBookmarksResult,
|
|
35
|
-
ListBookmarksResult,
|
|
36
|
-
ClearBookmarksResult,
|
|
37
|
-
} from "./pagination";
|
|
38
|
-
import type { StreamOptions, ExplainOptions } from "./stream";
|
|
39
|
-
import type { FindChain, AggregateChain } from "./chain";
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 健康视图
|
|
43
|
-
*/
|
|
44
|
-
export interface HealthView {
|
|
45
|
-
status: "up" | "down";
|
|
46
|
-
connected: boolean;
|
|
47
|
-
defaults?: any;
|
|
48
|
-
cache?: any;
|
|
49
|
-
driver?: { connected: boolean };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Collection 访问器接口
|
|
54
|
-
* 提供所有 Collection 操作方法
|
|
55
|
-
*/
|
|
56
|
-
export interface CollectionAccessor<TSchema = any> {
|
|
57
|
-
/**
|
|
58
|
-
* 获取命名空间信息
|
|
59
|
-
*/
|
|
60
|
-
getNamespace(): { iid: string; type: string; db: string; collection: string };
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 删除集合
|
|
64
|
-
*/
|
|
65
|
-
dropCollection(): Promise<boolean>;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 创建集合
|
|
69
|
-
*/
|
|
70
|
-
createCollection(name?: string | null, options?: any): Promise<boolean>;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* 创建视图
|
|
74
|
-
*/
|
|
75
|
-
createView(
|
|
76
|
-
viewName: string,
|
|
77
|
-
source: string,
|
|
78
|
-
pipeline?: any[],
|
|
79
|
-
): Promise<boolean>;
|
|
80
|
-
|
|
81
|
-
// ============================================================================
|
|
82
|
-
// 查询方法
|
|
83
|
-
// ============================================================================
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 查询单个文档
|
|
87
|
-
* 支持 meta 参数和泛型
|
|
88
|
-
*/
|
|
89
|
-
findOne<T = TSchema>(
|
|
90
|
-
query?: any,
|
|
91
|
-
options?: Omit<FindOptions, "meta">,
|
|
92
|
-
): Promise<T | null>;
|
|
93
|
-
findOne<T = TSchema>(
|
|
94
|
-
query: any,
|
|
95
|
-
options: FindOptions & { meta: true | MetaOptions },
|
|
96
|
-
): Promise<ResultWithMeta<T | null>>;
|
|
97
|
-
findOne<T = TSchema>(
|
|
98
|
-
query?: any,
|
|
99
|
-
options?: FindOptions,
|
|
100
|
-
): Promise<T | null | ResultWithMeta<T | null>>;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 通过 _id 查询单个文档(便利方法)
|
|
104
|
-
* @param id - 文档的 _id(字符串会自动转换为 ObjectId)
|
|
105
|
-
* @param options - 查询选项
|
|
106
|
-
*/
|
|
107
|
-
findOneById(
|
|
108
|
-
id: string | any,
|
|
109
|
-
options?: Omit<FindOptions, "meta">,
|
|
110
|
-
): Promise<any | null>;
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* 批量通过 _id 查询多个文档(便利方法)
|
|
114
|
-
* @param ids - _id 数组
|
|
115
|
-
* @param options - 查询选项
|
|
116
|
-
*/
|
|
117
|
-
findByIds(
|
|
118
|
-
ids: Array<string | any>,
|
|
119
|
-
options?: {
|
|
120
|
-
projection?: Record<string, any>;
|
|
121
|
-
sort?: Record<string, 1 | -1>;
|
|
122
|
-
cache?: number;
|
|
123
|
-
maxTimeMS?: number;
|
|
124
|
-
comment?: string;
|
|
125
|
-
preserveOrder?: boolean;
|
|
126
|
-
},
|
|
127
|
-
): Promise<any[]>;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* 查询多个文档
|
|
131
|
-
* 支持 meta 参数和链式调用
|
|
132
|
-
*/
|
|
133
|
-
find<T = TSchema>(query?: any): FindChain<T>;
|
|
134
|
-
find<T = TSchema>(
|
|
135
|
-
query: any,
|
|
136
|
-
options: FindOptions & { meta: true | MetaOptions },
|
|
137
|
-
): Promise<ResultWithMeta<T[]>>;
|
|
138
|
-
find<T = TSchema>(
|
|
139
|
-
query?: any,
|
|
140
|
-
options?: FindOptions,
|
|
141
|
-
): Promise<T[]> | FindChain<T> | ResultWithMeta<T[]>;
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* 计数
|
|
145
|
-
* 支持 meta 参数
|
|
146
|
-
*/
|
|
147
|
-
count(query?: any, options?: Omit<CountOptions, "meta">): Promise<number>;
|
|
148
|
-
count(
|
|
149
|
-
query: any,
|
|
150
|
-
options: CountOptions & { meta: true | MetaOptions },
|
|
151
|
-
): Promise<ResultWithMeta<number>>;
|
|
152
|
-
count(
|
|
153
|
-
query?: any,
|
|
154
|
-
options?: CountOptions,
|
|
155
|
-
): Promise<number | ResultWithMeta<number>>;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* 聚合查询
|
|
159
|
-
* 支持 meta 参数和链式调用
|
|
160
|
-
*/
|
|
161
|
-
aggregate<T = TSchema>(pipeline?: any[]): AggregateChain<T>;
|
|
162
|
-
aggregate<T = TSchema>(
|
|
163
|
-
pipeline: any[],
|
|
164
|
-
options: AggregateOptions & { meta: true | MetaOptions },
|
|
165
|
-
): Promise<ResultWithMeta<T[]>>;
|
|
166
|
-
aggregate<T = TSchema>(
|
|
167
|
-
pipeline?: any[],
|
|
168
|
-
options?: AggregateOptions,
|
|
169
|
-
): Promise<T[]> | AggregateChain<T> | ResultWithMeta<T[]>;
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 去重查询
|
|
173
|
-
* 支持 meta 参数
|
|
174
|
-
*/
|
|
175
|
-
distinct<T = any>(
|
|
176
|
-
field: string,
|
|
177
|
-
query?: any,
|
|
178
|
-
options?: Omit<DistinctOptions, "meta">,
|
|
179
|
-
): Promise<T[]>;
|
|
180
|
-
distinct<T = any>(
|
|
181
|
-
field: string,
|
|
182
|
-
query: any,
|
|
183
|
-
options: DistinctOptions & { meta: true | MetaOptions },
|
|
184
|
-
): Promise<ResultWithMeta<T[]>>;
|
|
185
|
-
distinct<T = any>(
|
|
186
|
-
field: string,
|
|
187
|
-
query?: any,
|
|
188
|
-
options?: DistinctOptions,
|
|
189
|
-
): Promise<T[] | ResultWithMeta<T[]>>;
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 流式查询
|
|
193
|
-
* 返回 Node.js 可读流
|
|
194
|
-
*/
|
|
195
|
-
stream(query?: any, options?: StreamOptions): NodeJS.ReadableStream;
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 查询执行计划诊断
|
|
199
|
-
*/
|
|
200
|
-
explain(query?: any, options?: ExplainOptions): Promise<any>;
|
|
201
|
-
|
|
202
|
-
// ============================================================================
|
|
203
|
-
// 分页相关
|
|
204
|
-
// ============================================================================
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* 深度分页
|
|
208
|
-
*/
|
|
209
|
-
findPage<T = TSchema>(options: FindPageOptions): Promise<PageResult<T>>;
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Bookmark 维护 APIs
|
|
213
|
-
*/
|
|
214
|
-
prewarmBookmarks(
|
|
215
|
-
keyDims: BookmarkKeyDims,
|
|
216
|
-
pages: number[],
|
|
217
|
-
): Promise<PrewarmBookmarksResult>;
|
|
218
|
-
listBookmarks(keyDims?: BookmarkKeyDims): Promise<ListBookmarksResult>;
|
|
219
|
-
clearBookmarks(keyDims?: BookmarkKeyDims): Promise<ClearBookmarksResult>;
|
|
220
|
-
|
|
221
|
-
// ============================================================================
|
|
222
|
-
// 写入操作
|
|
223
|
-
// ============================================================================
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* 插入单个文档
|
|
227
|
-
* 支持简化调用和完整配置
|
|
228
|
-
*/
|
|
229
|
-
insertOne<T = TSchema>(
|
|
230
|
-
document: T,
|
|
231
|
-
options?: InsertOneSimplifiedOptions,
|
|
232
|
-
): Promise<InsertOneResult>;
|
|
233
|
-
insertOne(options: InsertOneOptions): Promise<InsertOneResult>;
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* 插入多个文档
|
|
237
|
-
* 支持简化调用和完整配置
|
|
238
|
-
*/
|
|
239
|
-
insertMany<T = TSchema>(
|
|
240
|
-
documents: T[],
|
|
241
|
-
options?: InsertManySimplifiedOptions,
|
|
242
|
-
): Promise<InsertManyResult>;
|
|
243
|
-
insertMany(options: InsertManyOptions): Promise<InsertManyResult>;
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Upsert 单个文档(存在则更新,不存在则插入)
|
|
247
|
-
* @param filter - 查询条件
|
|
248
|
-
* @param update - 更新内容
|
|
249
|
-
* @param options - 操作选项
|
|
250
|
-
*/
|
|
251
|
-
upsertOne(
|
|
252
|
-
filter: Record<string, any>,
|
|
253
|
-
update: Record<string, any>,
|
|
254
|
-
options?: {
|
|
255
|
-
maxTimeMS?: number;
|
|
256
|
-
comment?: string;
|
|
257
|
-
},
|
|
258
|
-
): Promise<{
|
|
259
|
-
acknowledged: boolean;
|
|
260
|
-
matchedCount: number;
|
|
261
|
-
modifiedCount: number;
|
|
262
|
-
upsertedId?: any;
|
|
263
|
-
upsertedCount: number;
|
|
264
|
-
}>;
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* 原子递增/递减字段值(便利方法)
|
|
268
|
-
* @param filter - 查询条件
|
|
269
|
-
* @param field - 字段名或字段-增量对象
|
|
270
|
-
* @param increment - 增量(默认 1,负数为递减)
|
|
271
|
-
* @param options - 操作选项
|
|
272
|
-
*/
|
|
273
|
-
incrementOne(
|
|
274
|
-
filter: Record<string, any>,
|
|
275
|
-
field: string | Record<string, number>,
|
|
276
|
-
increment?: number,
|
|
277
|
-
options?: {
|
|
278
|
-
returnDocument?: "before" | "after";
|
|
279
|
-
projection?: Record<string, any>;
|
|
280
|
-
maxTimeMS?: number;
|
|
281
|
-
comment?: string;
|
|
282
|
-
},
|
|
283
|
-
): Promise<{
|
|
284
|
-
acknowledged: boolean;
|
|
285
|
-
matchedCount: number;
|
|
286
|
-
modifiedCount: number;
|
|
287
|
-
value: any | null;
|
|
288
|
-
}>;
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* 使缓存失效
|
|
292
|
-
*/
|
|
293
|
-
invalidate(
|
|
294
|
-
op?: "find" | "findOne" | "count" | "findPage" | "aggregate" | "distinct",
|
|
295
|
-
): Promise<number>;
|
|
296
|
-
|
|
297
|
-
// ============================================================================
|
|
298
|
-
// 批量操作
|
|
299
|
-
// ============================================================================
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* 大批量插入(自动分批+重试)
|
|
303
|
-
* @since v1.0.0
|
|
304
|
-
*/
|
|
305
|
-
insertBatch<T = TSchema>(
|
|
306
|
-
documents: T[],
|
|
307
|
-
options?: InsertBatchOptions,
|
|
308
|
-
): Promise<InsertBatchResult>;
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* 批量更新文档(流式查询+分批更新)
|
|
312
|
-
* @since v1.0.0
|
|
313
|
-
*/
|
|
314
|
-
updateBatch(
|
|
315
|
-
filter: Record<string, any>,
|
|
316
|
-
update: Record<string, any>,
|
|
317
|
-
options?: UpdateBatchOptions,
|
|
318
|
-
): Promise<UpdateBatchResult>;
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* 批量删除文档(流式查询+分批删除)
|
|
322
|
-
* @since v1.0.0
|
|
323
|
-
*/
|
|
324
|
-
deleteBatch(
|
|
325
|
-
filter: Record<string, any>,
|
|
326
|
-
options?: DeleteBatchOptions,
|
|
327
|
-
): Promise<DeleteBatchResult>;
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* 查询文档并返回总数(便利方法)
|
|
331
|
-
* @since v1.0.0
|
|
332
|
-
*/
|
|
333
|
-
findAndCount<T = TSchema>(
|
|
334
|
-
filter?: Record<string, any>,
|
|
335
|
-
options?: FindOptions,
|
|
336
|
-
): Promise<{ documents: T[]; total: number }>;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Collection 类型别名(与 CollectionAccessor 等价)
|
|
341
|
-
* @since v1.0.4
|
|
342
|
-
*/
|
|
343
|
-
export type Collection<TSchema = any> = CollectionAccessor<TSchema>;
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* 数据库访问器
|
|
347
|
-
*/
|
|
348
|
-
export type DbAccessor = {
|
|
349
|
-
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
350
|
-
db(dbName: string): {
|
|
351
|
-
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
352
|
-
};
|
|
353
|
-
/** `db()` 的别名,语义更清晰:`app.db.use('logs')` */
|
|
354
|
-
use(dbName: string): {
|
|
355
|
-
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
356
|
-
};
|
|
357
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Collection API 相关类型定义
|
|
3
|
+
* @module types/collection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
FindOptions,
|
|
8
|
+
CountOptions,
|
|
9
|
+
AggregateOptions,
|
|
10
|
+
DistinctOptions,
|
|
11
|
+
} from "./query";
|
|
12
|
+
import type {
|
|
13
|
+
InsertOneSimplifiedOptions,
|
|
14
|
+
InsertOneOptions,
|
|
15
|
+
InsertOneResult,
|
|
16
|
+
InsertManySimplifiedOptions,
|
|
17
|
+
InsertManyOptions,
|
|
18
|
+
InsertManyResult,
|
|
19
|
+
} from "./write";
|
|
20
|
+
import type {
|
|
21
|
+
InsertBatchOptions,
|
|
22
|
+
InsertBatchResult,
|
|
23
|
+
UpdateBatchOptions,
|
|
24
|
+
UpdateBatchResult,
|
|
25
|
+
DeleteBatchOptions,
|
|
26
|
+
DeleteBatchResult,
|
|
27
|
+
} from "./batch";
|
|
28
|
+
import type {
|
|
29
|
+
FindPageOptions,
|
|
30
|
+
PageResult,
|
|
31
|
+
ResultWithMeta,
|
|
32
|
+
MetaOptions,
|
|
33
|
+
BookmarkKeyDims,
|
|
34
|
+
PrewarmBookmarksResult,
|
|
35
|
+
ListBookmarksResult,
|
|
36
|
+
ClearBookmarksResult,
|
|
37
|
+
} from "./pagination";
|
|
38
|
+
import type { StreamOptions, ExplainOptions } from "./stream";
|
|
39
|
+
import type { FindChain, AggregateChain } from "./chain";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 健康视图
|
|
43
|
+
*/
|
|
44
|
+
export interface HealthView {
|
|
45
|
+
status: "up" | "down";
|
|
46
|
+
connected: boolean;
|
|
47
|
+
defaults?: any;
|
|
48
|
+
cache?: any;
|
|
49
|
+
driver?: { connected: boolean };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Collection 访问器接口
|
|
54
|
+
* 提供所有 Collection 操作方法
|
|
55
|
+
*/
|
|
56
|
+
export interface CollectionAccessor<TSchema = any> {
|
|
57
|
+
/**
|
|
58
|
+
* 获取命名空间信息
|
|
59
|
+
*/
|
|
60
|
+
getNamespace(): { iid: string; type: string; db: string; collection: string };
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 删除集合
|
|
64
|
+
*/
|
|
65
|
+
dropCollection(): Promise<boolean>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 创建集合
|
|
69
|
+
*/
|
|
70
|
+
createCollection(name?: string | null, options?: any): Promise<boolean>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 创建视图
|
|
74
|
+
*/
|
|
75
|
+
createView(
|
|
76
|
+
viewName: string,
|
|
77
|
+
source: string,
|
|
78
|
+
pipeline?: any[],
|
|
79
|
+
): Promise<boolean>;
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// 查询方法
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 查询单个文档
|
|
87
|
+
* 支持 meta 参数和泛型
|
|
88
|
+
*/
|
|
89
|
+
findOne<T = TSchema>(
|
|
90
|
+
query?: any,
|
|
91
|
+
options?: Omit<FindOptions, "meta">,
|
|
92
|
+
): Promise<T | null>;
|
|
93
|
+
findOne<T = TSchema>(
|
|
94
|
+
query: any,
|
|
95
|
+
options: FindOptions & { meta: true | MetaOptions },
|
|
96
|
+
): Promise<ResultWithMeta<T | null>>;
|
|
97
|
+
findOne<T = TSchema>(
|
|
98
|
+
query?: any,
|
|
99
|
+
options?: FindOptions,
|
|
100
|
+
): Promise<T | null | ResultWithMeta<T | null>>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 通过 _id 查询单个文档(便利方法)
|
|
104
|
+
* @param id - 文档的 _id(字符串会自动转换为 ObjectId)
|
|
105
|
+
* @param options - 查询选项
|
|
106
|
+
*/
|
|
107
|
+
findOneById(
|
|
108
|
+
id: string | any,
|
|
109
|
+
options?: Omit<FindOptions, "meta">,
|
|
110
|
+
): Promise<any | null>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 批量通过 _id 查询多个文档(便利方法)
|
|
114
|
+
* @param ids - _id 数组
|
|
115
|
+
* @param options - 查询选项
|
|
116
|
+
*/
|
|
117
|
+
findByIds(
|
|
118
|
+
ids: Array<string | any>,
|
|
119
|
+
options?: {
|
|
120
|
+
projection?: Record<string, any>;
|
|
121
|
+
sort?: Record<string, 1 | -1>;
|
|
122
|
+
cache?: number;
|
|
123
|
+
maxTimeMS?: number;
|
|
124
|
+
comment?: string;
|
|
125
|
+
preserveOrder?: boolean;
|
|
126
|
+
},
|
|
127
|
+
): Promise<any[]>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 查询多个文档
|
|
131
|
+
* 支持 meta 参数和链式调用
|
|
132
|
+
*/
|
|
133
|
+
find<T = TSchema>(query?: any): FindChain<T>;
|
|
134
|
+
find<T = TSchema>(
|
|
135
|
+
query: any,
|
|
136
|
+
options: FindOptions & { meta: true | MetaOptions },
|
|
137
|
+
): Promise<ResultWithMeta<T[]>>;
|
|
138
|
+
find<T = TSchema>(
|
|
139
|
+
query?: any,
|
|
140
|
+
options?: FindOptions,
|
|
141
|
+
): Promise<T[]> | FindChain<T> | ResultWithMeta<T[]>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 计数
|
|
145
|
+
* 支持 meta 参数
|
|
146
|
+
*/
|
|
147
|
+
count(query?: any, options?: Omit<CountOptions, "meta">): Promise<number>;
|
|
148
|
+
count(
|
|
149
|
+
query: any,
|
|
150
|
+
options: CountOptions & { meta: true | MetaOptions },
|
|
151
|
+
): Promise<ResultWithMeta<number>>;
|
|
152
|
+
count(
|
|
153
|
+
query?: any,
|
|
154
|
+
options?: CountOptions,
|
|
155
|
+
): Promise<number | ResultWithMeta<number>>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 聚合查询
|
|
159
|
+
* 支持 meta 参数和链式调用
|
|
160
|
+
*/
|
|
161
|
+
aggregate<T = TSchema>(pipeline?: any[]): AggregateChain<T>;
|
|
162
|
+
aggregate<T = TSchema>(
|
|
163
|
+
pipeline: any[],
|
|
164
|
+
options: AggregateOptions & { meta: true | MetaOptions },
|
|
165
|
+
): Promise<ResultWithMeta<T[]>>;
|
|
166
|
+
aggregate<T = TSchema>(
|
|
167
|
+
pipeline?: any[],
|
|
168
|
+
options?: AggregateOptions,
|
|
169
|
+
): Promise<T[]> | AggregateChain<T> | ResultWithMeta<T[]>;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 去重查询
|
|
173
|
+
* 支持 meta 参数
|
|
174
|
+
*/
|
|
175
|
+
distinct<T = any>(
|
|
176
|
+
field: string,
|
|
177
|
+
query?: any,
|
|
178
|
+
options?: Omit<DistinctOptions, "meta">,
|
|
179
|
+
): Promise<T[]>;
|
|
180
|
+
distinct<T = any>(
|
|
181
|
+
field: string,
|
|
182
|
+
query: any,
|
|
183
|
+
options: DistinctOptions & { meta: true | MetaOptions },
|
|
184
|
+
): Promise<ResultWithMeta<T[]>>;
|
|
185
|
+
distinct<T = any>(
|
|
186
|
+
field: string,
|
|
187
|
+
query?: any,
|
|
188
|
+
options?: DistinctOptions,
|
|
189
|
+
): Promise<T[] | ResultWithMeta<T[]>>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 流式查询
|
|
193
|
+
* 返回 Node.js 可读流
|
|
194
|
+
*/
|
|
195
|
+
stream(query?: any, options?: StreamOptions): NodeJS.ReadableStream;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 查询执行计划诊断
|
|
199
|
+
*/
|
|
200
|
+
explain(query?: any, options?: ExplainOptions): Promise<any>;
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// 分页相关
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 深度分页
|
|
208
|
+
*/
|
|
209
|
+
findPage<T = TSchema>(options: FindPageOptions): Promise<PageResult<T>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Bookmark 维护 APIs
|
|
213
|
+
*/
|
|
214
|
+
prewarmBookmarks(
|
|
215
|
+
keyDims: BookmarkKeyDims,
|
|
216
|
+
pages: number[],
|
|
217
|
+
): Promise<PrewarmBookmarksResult>;
|
|
218
|
+
listBookmarks(keyDims?: BookmarkKeyDims): Promise<ListBookmarksResult>;
|
|
219
|
+
clearBookmarks(keyDims?: BookmarkKeyDims): Promise<ClearBookmarksResult>;
|
|
220
|
+
|
|
221
|
+
// ============================================================================
|
|
222
|
+
// 写入操作
|
|
223
|
+
// ============================================================================
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 插入单个文档
|
|
227
|
+
* 支持简化调用和完整配置
|
|
228
|
+
*/
|
|
229
|
+
insertOne<T = TSchema>(
|
|
230
|
+
document: T,
|
|
231
|
+
options?: InsertOneSimplifiedOptions,
|
|
232
|
+
): Promise<InsertOneResult>;
|
|
233
|
+
insertOne(options: InsertOneOptions): Promise<InsertOneResult>;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 插入多个文档
|
|
237
|
+
* 支持简化调用和完整配置
|
|
238
|
+
*/
|
|
239
|
+
insertMany<T = TSchema>(
|
|
240
|
+
documents: T[],
|
|
241
|
+
options?: InsertManySimplifiedOptions,
|
|
242
|
+
): Promise<InsertManyResult>;
|
|
243
|
+
insertMany(options: InsertManyOptions): Promise<InsertManyResult>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Upsert 单个文档(存在则更新,不存在则插入)
|
|
247
|
+
* @param filter - 查询条件
|
|
248
|
+
* @param update - 更新内容
|
|
249
|
+
* @param options - 操作选项
|
|
250
|
+
*/
|
|
251
|
+
upsertOne(
|
|
252
|
+
filter: Record<string, any>,
|
|
253
|
+
update: Record<string, any>,
|
|
254
|
+
options?: {
|
|
255
|
+
maxTimeMS?: number;
|
|
256
|
+
comment?: string;
|
|
257
|
+
},
|
|
258
|
+
): Promise<{
|
|
259
|
+
acknowledged: boolean;
|
|
260
|
+
matchedCount: number;
|
|
261
|
+
modifiedCount: number;
|
|
262
|
+
upsertedId?: any;
|
|
263
|
+
upsertedCount: number;
|
|
264
|
+
}>;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 原子递增/递减字段值(便利方法)
|
|
268
|
+
* @param filter - 查询条件
|
|
269
|
+
* @param field - 字段名或字段-增量对象
|
|
270
|
+
* @param increment - 增量(默认 1,负数为递减)
|
|
271
|
+
* @param options - 操作选项
|
|
272
|
+
*/
|
|
273
|
+
incrementOne(
|
|
274
|
+
filter: Record<string, any>,
|
|
275
|
+
field: string | Record<string, number>,
|
|
276
|
+
increment?: number,
|
|
277
|
+
options?: {
|
|
278
|
+
returnDocument?: "before" | "after";
|
|
279
|
+
projection?: Record<string, any>;
|
|
280
|
+
maxTimeMS?: number;
|
|
281
|
+
comment?: string;
|
|
282
|
+
},
|
|
283
|
+
): Promise<{
|
|
284
|
+
acknowledged: boolean;
|
|
285
|
+
matchedCount: number;
|
|
286
|
+
modifiedCount: number;
|
|
287
|
+
value: any | null;
|
|
288
|
+
}>;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 使缓存失效
|
|
292
|
+
*/
|
|
293
|
+
invalidate(
|
|
294
|
+
op?: "find" | "findOne" | "count" | "findPage" | "aggregate" | "distinct",
|
|
295
|
+
): Promise<number>;
|
|
296
|
+
|
|
297
|
+
// ============================================================================
|
|
298
|
+
// 批量操作
|
|
299
|
+
// ============================================================================
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 大批量插入(自动分批+重试)
|
|
303
|
+
* @since v1.0.0
|
|
304
|
+
*/
|
|
305
|
+
insertBatch<T = TSchema>(
|
|
306
|
+
documents: T[],
|
|
307
|
+
options?: InsertBatchOptions,
|
|
308
|
+
): Promise<InsertBatchResult>;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 批量更新文档(流式查询+分批更新)
|
|
312
|
+
* @since v1.0.0
|
|
313
|
+
*/
|
|
314
|
+
updateBatch(
|
|
315
|
+
filter: Record<string, any>,
|
|
316
|
+
update: Record<string, any>,
|
|
317
|
+
options?: UpdateBatchOptions,
|
|
318
|
+
): Promise<UpdateBatchResult>;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* 批量删除文档(流式查询+分批删除)
|
|
322
|
+
* @since v1.0.0
|
|
323
|
+
*/
|
|
324
|
+
deleteBatch(
|
|
325
|
+
filter: Record<string, any>,
|
|
326
|
+
options?: DeleteBatchOptions,
|
|
327
|
+
): Promise<DeleteBatchResult>;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* 查询文档并返回总数(便利方法)
|
|
331
|
+
* @since v1.0.0
|
|
332
|
+
*/
|
|
333
|
+
findAndCount<T = TSchema>(
|
|
334
|
+
filter?: Record<string, any>,
|
|
335
|
+
options?: FindOptions,
|
|
336
|
+
): Promise<{ documents: T[]; total: number }>;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Collection 类型别名(与 CollectionAccessor 等价)
|
|
341
|
+
* @since v1.0.4
|
|
342
|
+
*/
|
|
343
|
+
export type Collection<TSchema = any> = CollectionAccessor<TSchema>;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* 数据库访问器
|
|
347
|
+
*/
|
|
348
|
+
export type DbAccessor = {
|
|
349
|
+
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
350
|
+
db(dbName: string): {
|
|
351
|
+
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
352
|
+
};
|
|
353
|
+
/** `db()` 的别名,语义更清晰:`app.db.use('logs')` */
|
|
354
|
+
use(dbName: string): {
|
|
355
|
+
collection<TSchema = any>(name: string): CollectionAccessor<TSchema>;
|
|
356
|
+
};
|
|
357
|
+
};
|