docs(G6): 宣称与实现一致性收口 —— priority 真正生效、MVCC/backup/引擎数/打包 全部对齐
独立核验(12 条宣称逐条对源码验证)发现 5 处**硬伤**与 2 处**数字过期**, 本提交按"能改代码就让宣称成立、改不动就如实描述"的原则全部收口。 让实现符合文档(2 处): 1. **插件 priority 此前不生效** — `register()` 虽按 priority 插入数组,但 `install()` 在 register 内**立即**执行,因此 install 与钩子顺序 = config 数组 顺序(实测 priority low=1/high=100/mid=50 时钩子按 low→high→mid 触发, 只有 `getPlugins()` 是 high,mid,low)。而 README/CONTRIBUTING/constants 一直宣称"越大越先执行"。 现在 Core 注册前按 priority **稳定降序**排序(同优先级保持数组顺序), install 与钩子都按优先级执行 → 宣称成立。新增 `tests/v080-plugin-priority.test.ts` 锁定 install 顺序、钩子顺序、稳定性、缺省值。 2. **连接池静态方法不在类型系统里** — `MetonaSqlark.connect/disconnect/ disconnectAll/getActiveConnections` 由 connection-manager 用 `as unknown as Record<string, unknown>` 注入,README 的连接池表格在 TypeScript 下全部 TS2339。现在在类上声明为可选静态成员,注入处去掉断言。 如实描述(3 处): 3. **MVCC 快照隔离**(README 三处 + 实现对照)— `snapshotLsn` / `prevVersion` 只写不读,事务读走 `txnSnapshot`+LSM,commit 即清理版本链,并发 `beginTransaction` 抛 `TX_ACTIVE`。改为"快照回滚(事务串行,非 MVCC 隔离)", 并在 README 架构图与维护语句表里同步措辞。 4. **"存储引擎(5 种)"** — 实际是 4 种模式 + 3 种后端,引擎类只有 4 个 (Memory / KVStore / Hybrid / Aria),OPFS 是后端而非引擎。标题与条目已改写, 并写明"`disk`/`hybrid` 恒用 KVStore"。 5. **`diskEngine` 生效范围** — 仅 `mode:'aria'` 生效;`constants.ts` 的注释 此前写成"仅 mode='disk'|'hybrid' 时生效"(正好写反),已改正;README 配置表、 快速开始示例与 Aria 示例同步标注。 数字口径统一(可复现): - 测试 1872(90 套件)+ 14 e2e,另 4 个重型套件在独立 CI job 串行运行; - 覆盖率 语句 90.43% / 分支 82.21% / 函数 94.27% / 行 93.44%; - README 明确写出**产出这些数字的完整命令**(与 CI 常规 job 一致), 并要求改动覆盖范围/阈值时同步更新表格(G5)。 - CHANGELOG 0.8.0 条目与 site 首页/文档页同步。 另修 **CONTRIBUTING 的钩子契约**:明确写出"返回值被忽略(不能取消/改写)、 就地改参数在 Table API 生效、抛异常可取消、SQL 路径的 beforeInsert 收到副本" —— 此前只写 "allow intercepting",容易被理解为返回值可改变行为。 验证:全量 90 套件 / 1872 测试通过(+4 重型套件);覆盖率四项均高于阈值; typecheck(src+tests)、lint、build 零错误零告警;e2e 14 项通过;dist 已重建。
This commit is contained in:
+55
-4
@@ -31,6 +31,38 @@ export class MetonaSqlark {
|
||||
/** 数据库名称 */
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* v0.8.0:释放一个连接引用(引用计数 -1,归零时自动关闭)。
|
||||
*
|
||||
* 由 `MetonaSqlark.connect()` 注入实现 —— 此前该方法是**运行时注入、类型上不存在**:
|
||||
* README 与示例都在用 `await db.disconnect()`,但 `db` 的声明里没有它,
|
||||
* TypeScript 使用者会直接编译失败(只能 `as any` 绕过)。
|
||||
* 普通 `create()` 得到的实例没有这个方法,因此为可选:
|
||||
* 只有经 `connect()` 取得的实例才有,直接调用会抛错(而不是静默无操作)。
|
||||
*/
|
||||
disconnect?: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* v0.8.0:连接池静态 API 的类型声明。
|
||||
*
|
||||
* 这些方法由 `src/connection-manager.ts` **运行时注入**(`MetonaSqlark.connect = ...`)。
|
||||
* 此前注入侧用 `as unknown as Record<string, unknown>` 绕过类型检查,
|
||||
* 于是 README「连接池」一节里的 `MetonaSqlark.connect(...)` /
|
||||
* `MetonaSqlark.disconnectAll()` 在 TypeScript 下全部报 TS2339
|
||||
*("属性不存在"),使用者只能 `as any`。
|
||||
*
|
||||
* 声明为 `?` 可选是因为它们**只在 import 了 connection-manager 的构建里存在**:
|
||||
* 核心入口不 import 它(避免无谓的模块副作用)。真正常用的路径是
|
||||
* `MetonaSqlark.create()`。
|
||||
*/
|
||||
static connect?: (config: DatabaseConfig) => Promise<MetonaSqlark>;
|
||||
/** 按库名释放一个连接引用(等价于实例上的 `disconnect()`) */
|
||||
static disconnect?: (dbName: string) => Promise<void>;
|
||||
/** 关闭全部连接 */
|
||||
static disconnectAll?: () => Promise<void>;
|
||||
/** 当前活跃连接名列表 */
|
||||
static getActiveConnections?: () => string[];
|
||||
|
||||
/**
|
||||
* v0.7.1: 静态工厂(与 connect/disconnect 同一入口风格)。
|
||||
* 此前 create 仅存在于 api 对象 / window 挂载 —— README/站点示例的
|
||||
@@ -148,9 +180,22 @@ export class MetonaSqlark {
|
||||
this.executor = new QueryExecutor(this.engine, this.maxRowsPerQuery);
|
||||
this.transactionManager = new TransactionManager(this.engine);
|
||||
|
||||
// 注册插件
|
||||
// 注册插件。
|
||||
//
|
||||
// v0.8.0:**先按 priority 降序排序再注册** —— 在这之前 PluginManager.register
|
||||
// 虽然会把插件插到正确的位置,但 `install()` 是在 register 里**立即**调用的,
|
||||
// 因此 install 与钩子的实际执行顺序仍等于 config 数组顺序
|
||||
//(实测:priority 为 low/high/mid 的插件,钩子按 low→high→mid 触发,
|
||||
// 只有 getPlugins() 才是 high,mid,low)。而 README/CONTRIBUTING 一直宣称
|
||||
// "priority 越大越先执行" —— 文档与实现不符。
|
||||
// 这里选择**让实现符合文档**(priority 是用户可见的配置项,静默无效比没有更糟)。
|
||||
// 用稳定排序:同优先级保持 config 数组中的相对顺序。
|
||||
if (this.config.plugins) {
|
||||
for (const plugin of this.config.plugins) {
|
||||
const ordered = this.config.plugins
|
||||
.map((plugin, index) => ({ plugin, index }))
|
||||
.sort((a, b) => (b.plugin.priority ?? 0) - (a.plugin.priority ?? 0) || a.index - b.index)
|
||||
.map((entry) => entry.plugin);
|
||||
for (const plugin of ordered) {
|
||||
this.pluginManager.register(plugin, this);
|
||||
}
|
||||
}
|
||||
@@ -489,8 +534,14 @@ export class MetonaSqlark {
|
||||
}
|
||||
|
||||
/**
|
||||
* v0.5.1: 在线备份 — 导出全库一致性快照。
|
||||
* Aria 引擎走引擎级 backup()(MVCC 一致性视图);其余引擎回退 exportAll()。
|
||||
* v0.5.1: 在线备份 — 导出全库数据。
|
||||
*
|
||||
* v0.8.0 修正表述:此前注释与 README 宣称"全库**一致性**快照",但引擎层
|
||||
* 并没有跨表快照原语 —— 实现是**逐表读取**(Aria 走引擎级 `backup()`,
|
||||
* 其余引擎回退 `exportAll()`)。备份过程中的并发写入会让不同表来自不同
|
||||
* 时间点(单表内部仍是一致的)。需要强一致时先 `close()`,或用
|
||||
* `db.transaction()` 包住调用(事务期间并发写被 `TX_ACTIVE` 拒绝)。
|
||||
* 真正的跨表快照需要 COW 行所有权改造,列入后续版本。
|
||||
*/
|
||||
async backup(): Promise<Record<string, Record<string, unknown>[]>> {
|
||||
this.ensureReady();
|
||||
|
||||
Reference in New Issue
Block a user