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
+57
View File
@@ -184,4 +184,61 @@ describe('migrateFromIndexedDB', () => {
.rejects.toThrow('not supported');
await target.close();
});
it('无 id 列的旧库:第一个非 json 列兜底为主键(v0.7.3', async () => {
const legacyName = uniqueDB();
await new Promise<void>((resolve, reject) => {
const request = indexedDB.open(legacyName, 1);
request.onupgradeneeded = () => {
request.result.createObjectStore('nokey_tbl', { autoIncrement: true });
};
request.onsuccess = () => {
const db = request.result;
const tx = db.transaction('nokey_tbl', 'readwrite');
tx.objectStore('nokey_tbl').add({ code: 'c1', name: 'X' });
tx.objectStore('nokey_tbl').add({ code: 'c2', name: 'Y' });
tx.oncomplete = () => { db.close(); resolve(); };
tx.onerror = () => reject(tx.error);
};
request.onerror = () => reject(request.error);
});
const target = new MetonaSqlark({ name: uniqueDB(), mode: 'disk' });
await target.init();
// 此前无主键 → createSchema 抛 SCHEMA_ERROR 中断整个迁移;现在 code 列兜底为主键
const result = await migrateFromIndexedDB({ dbName: legacyName, engine: 'disk', target });
expect(result.migratedTables).toEqual(['nokey_tbl']);
expect(result.rowCount).toBe(2);
const rows = await target.table('nokey_tbl').select().execute();
expect(rows).toHaveLength(2);
await target.close();
});
it('全 json 列的旧库:无可用主键 → 跳过该表不中断迁移(v0.7.3)', async () => {
const legacyName = uniqueDB();
await new Promise<void>((resolve, reject) => {
const request = indexedDB.open(legacyName, 1);
request.onupgradeneeded = () => {
request.result.createObjectStore('json_tbl', { autoIncrement: true });
request.result.createObjectStore('ok_tbl', { keyPath: 'id' });
};
request.onsuccess = () => {
const db = request.result;
const tx = db.transaction(['json_tbl', 'ok_tbl'], 'readwrite');
tx.objectStore('json_tbl').add({ payload: { a: 1 } });
tx.objectStore('ok_tbl').add({ id: '1', name: 'Z' });
tx.oncomplete = () => { db.close(); resolve(); };
tx.onerror = () => reject(tx.error);
};
request.onerror = () => reject(request.error);
});
const target = new MetonaSqlark({ name: uniqueDB(), mode: 'disk' });
await target.init();
const result = await migrateFromIndexedDB({ dbName: legacyName, engine: 'disk', target });
// json_tbl 无可用主键被跳过;ok_tbl 正常迁移
expect(result.skippedTables).toContain('json_tbl');
expect(result.migratedTables).toEqual(['ok_tbl']);
await target.close();
});
});