release: v0.6.0 — 完全移除 IndexedDB,自研 KVStore 事务存储引擎(多key原子写/快照日志恢复/CRC自愈)+ KVStoreEngine + 旧库迁移工具 + 10万级压力验证 + 崩溃注入e2e
CI / test (20.x) (push) Successful in 10m53s
CI / test (22.x) (push) Successful in 10m47s
CI / test (24.x) (push) Successful in 10m42s
CI / e2e (push) Successful in 10m27s
CI / test (18.x) (push) Successful in 11m1s

This commit is contained in:
thzxx
2026-08-10 13:56:04 +08:00
parent 2668bd47cf
commit 24b3ca1079
74 changed files with 8016 additions and 7688 deletions
+4 -111
View File
@@ -4,9 +4,7 @@
*/
import { MemoryEngine } from '../src/engine/memory';
import { IndexedDBEngine } from '../src/engine/indexeddb';
import { MetonaSqlark } from '../src/core';
import 'fake-indexeddb/auto';
let idbCounter = 0;
@@ -51,75 +49,6 @@ describe('v0.1.14 幂等 init — MemoryEngine', () => {
});
// ===================================================================
// IndexedDB flushToIDB 原子性
// ===================================================================
describe('v0.1.14 原子性 flush — IndexedDBEngine', () => {
let engine: IndexedDBEngine;
let dbName: string;
beforeEach(async () => {
dbName = uniqueDB();
engine = new IndexedDBEngine();
await engine.open(dbName, 1);
});
afterEach(async () => {
try { await engine.close(); } catch {}
try { indexedDB.deleteDatabase(dbName); } catch {}
});
it('事务 commit 后内存数据完整', async () => {
await engine.createTable({ name: 'users', columns: { id: { type: 'string', primaryKey: true }, name: { type: 'string' } } });
await engine.beginTransaction();
await engine.insert('users', [{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }]);
await engine.commitTransaction();
const rows = await engine.find('users', { table: 'users' });
expect(rows).toHaveLength(2);
});
it('事务 commit 后混合操作数据完整', async () => {
await engine.createTable({ name: 'users', columns: { id: { type: 'string', primaryKey: true }, name: { type: 'string' } } });
await engine.insert('users', [{ id: '1', name: 'Alice' }]);
await engine.beginTransaction();
await engine.insert('users', [{ id: '2', name: 'Bob' }]);
await engine.update('users', { table: 'users', where: { id: '1' } }, { name: 'Alice2' });
await engine.delete('users', { table: 'users', where: { id: '2' } });
await engine.commitTransaction();
const rows = await engine.find('users', { table: 'users' });
expect(rows).toHaveLength(1);
expect(rows[0].name).toBe('Alice2');
});
it('事务回滚后数据完全恢复', async () => {
await engine.createTable({ name: 'users', columns: { id: { type: 'string', primaryKey: true }, name: { type: 'string' } } });
await engine.insert('users', [{ id: '1', name: 'Alice' }]);
await engine.beginTransaction();
await engine.insert('users', [{ id: '2', name: 'Bob' }]);
await engine.rollbackTransaction();
const rows = await engine.find('users', { table: 'users' });
expect(rows).toHaveLength(1);
expect(rows[0].name).toBe('Alice');
});
it('事务内的 find 能读到未提交的变更', async () => {
await engine.createTable({ name: 'users', columns: { id: { type: 'string', primaryKey: true }, name: { type: 'string' } } });
await engine.insert('users', [{ id: '1', name: 'Alice' }]);
await engine.beginTransaction();
await engine.insert('users', [{ id: '2', name: 'Bob' }]);
// 事务内的 find 应能读到事务写入的数据
const rows = await engine.find('users', { table: 'users' });
expect(rows).toHaveLength(2);
await engine.rollbackTransaction();
});
});
// ===================================================================
// Hybrid 引擎事务持久化
// ===================================================================
@@ -130,7 +59,7 @@ describe('v0.1.14 Hybrid 引擎事务持久化', () => {
beforeEach(async () => {
dbName = uniqueDB();
db = new MetonaSqlark({ name: dbName, mode: 'hybrid', diskEngine: 'indexeddb' });
db = new MetonaSqlark({ name: dbName, mode: 'hybrid', diskEngine: 'opfs' });
await db.init();
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
@@ -140,7 +69,6 @@ describe('v0.1.14 Hybrid 引擎事务持久化', () => {
afterEach(async () => {
await db.close();
try { indexedDB.deleteDatabase(dbName); } catch {}
});
it('Hybrid 事务 commit 后内存和磁盘一致', async () => {
@@ -153,16 +81,11 @@ describe('v0.1.14 Hybrid 引擎事务持久化', () => {
const rows = await db.table('users').select().execute();
expect(rows).toHaveLength(2);
// 重新连接同一数据库(先关闭再创建新实例,但要先 deleteDatabase 让 fake-idb 干净)
// 重新打开同一库:Hybrid 从磁盘(KVStore)恢复已提交事务数据
await db.close();
try { indexedDB.deleteDatabase(dbName); } catch {}
// 用新实例打开(验证内存+磁盘一致性:Hybrid 应该从磁盘恢复)
const db2 = new MetonaSqlark({ name: dbName, mode: 'hybrid', diskEngine: 'indexeddb' });
const db2 = new MetonaSqlark({ name: dbName, mode: 'hybrid', diskEngine: 'opfs' });
await db2.init();
// 新数据库是空的(因为删了 IDB),Hybrid 从磁盘加载也是空的
const names2 = await db2.getTableNames();
expect(names2).toHaveLength(0);
expect(await db2.table('users').count()).toBe(2);
await db2.close();
});
@@ -181,33 +104,3 @@ describe('v0.1.14 Hybrid 引擎事务持久化', () => {
expect(rows[0].id).toBe('1');
});
});
// ===================================================================
// onversionchange 监听
// ===================================================================
describe('v0.1.14 onversionchange — IndexedDBEngine', () => {
it('open 后 onversionchange 回调已绑定', async () => {
const dbName = uniqueDB();
const engine = new IndexedDBEngine();
await engine.open(dbName, 1);
const rawDb = (engine as any).db;
expect(rawDb).toBeTruthy();
expect(typeof rawDb.onversionchange).toBe('function');
await engine.close();
try { indexedDB.deleteDatabase(dbName); } catch {}
});
it('close 后 db 引用和监听器均被清理', async () => {
const dbName = uniqueDB();
const engine = new IndexedDBEngine();
await engine.open(dbName, 1);
await engine.close();
const rawDb = (engine as any).db;
expect(rawDb).toBeNull();
try { indexedDB.deleteDatabase(dbName); } catch {}
});
});