fix: v0.7.3 数据正确性与边界窗口收尾 — INSERT 语句级原子(三引擎+Aria PK 批内重复)/ 索引列 IS NULL 恒空 / delete RESTRICT 破坏索引 / queryStream 子查询静默空结果 / ALTER DROP 索引残留 / UNIQUE INDEX 存量校验 / SELECT * 别名投影 / WAL BEGIN/ROLLBACK 事务边界 / aria $in 与级联重复扫描性能 / $and 等值下推 / ANALYZE 索引统计 / React-Vue hooks 生命周期 / 迁移主键兜底 + 58 回归
CI / test (18.x) (push) Successful in 17m43s
CI / test (22.x) (push) Successful in 13m45s
CI / test (20.x) (push) Successful in 15m33s
CI / test (24.x) (push) Successful in 24m46s
CI / e2e (push) Successful in 52s

This commit is contained in:
thzxx
2026-08-14 22:53:46 +08:00
parent f8f8d1b2ff
commit 50468b9b0e
29 changed files with 2374 additions and 650 deletions
+35
View File
@@ -13,6 +13,7 @@
// ---- 最小 Vue mock(自包含:jest.mock 工厂不能引用外部变量) ----
jest.mock('vue', () => {
const mountQueue: Array<() => void | Promise<void>> = [];
const unmountQueue: Array<() => void | Promise<void>> = [];
const watchList: Array<{ sources: any[]; cb: () => void | Promise<void> }> = [];
return {
ref: (init: any) => {
@@ -25,10 +26,15 @@ jest.mock('vue', () => {
onMounted: (fn: any) => {
mountQueue.push(fn);
},
onUnmounted: (fn: any) => {
unmountQueue.push(fn);
},
__mockMounted: mountQueue,
__mockUnmounted: unmountQueue,
__mockWatch: watchList,
__mockReset: () => {
mountQueue.length = 0;
unmountQueue.length = 0;
watchList.length = 0;
},
};
@@ -39,6 +45,7 @@ import { useSqlarkQuery, useSqlarkTable, useSqlarkDatabase } from '../../src/int
/** mock 模块内的挂载/监听队列(自包含作用域) */
const vueMock = jest.requireMock('vue') as {
__mockMounted: Array<() => void | Promise<void>>;
__mockUnmounted: Array<() => void | Promise<void>>;
__mockWatch: Array<{ sources: any[]; cb: () => void | Promise<void> }>;
__mockReset: () => void;
};
@@ -55,6 +62,14 @@ async function flushMounted(): Promise<void> {
}
}
/** 模拟组件卸载:执行 onUnmounted 注册的回调 */
async function flushUnmounted(): Promise<void> {
const fns = vueMock.__mockUnmounted.splice(0);
for (const fn of fns) {
await fn();
}
}
/** 触发 watch 回调 */
async function flushWatch(): Promise<void> {
const pairs = vueMock.__mockWatch.splice(0);
@@ -163,4 +178,24 @@ describe('useSqlarkDatabase', () => {
expect(hook.ready.value).toBe(false);
expect(hook.error.value).toBeInstanceOf(Error);
});
test('组件卸载时关闭数据库实例(v0.7.3)', async () => {
const hook = useSqlarkDatabase({ name: 'vue-unmount', mode: 'memory' });
await flushMounted();
expect(hook.db.value).not.toBeNull();
const db = hook.db.value!;
// 实例打开中:isReady
expect(db.isReady()).toBe(true);
await flushUnmounted();
// close 后实例不可再查询
await expect(db.query('SELECT 1')).rejects.toMatchObject({ code: 'DB_NOT_READY' });
});
test('卸载时实例为 null 不抛错(初始化失败场景)', async () => {
const hook = useSqlarkDatabase({ name: 'vue-unmount-fail', mode: 'unknown-mode' as any });
await flushMounted();
await expect(flushUnmounted()).resolves.toBeUndefined();
expect(hook.db.value).toBeNull();
});
});