/** * IndexedDBEngine 完整测试(使用 fake-indexeddb) * 每次测试使用独立的数据库名避免版本冲突 */ import 'fake-indexeddb/auto'; import { IndexedDBEngine } from '../../src/engine/indexeddb'; import { createSchema } from '../../src/table/schema'; let dbCounter = 0; describe('IndexedDBEngine', () => { let engine: IndexedDBEngine; let dbName: string; const userSchema = createSchema('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string', required: true }, age: { type: 'number', default: 0 }, email: { type: 'string', unique: true }, }); beforeEach(async () => { dbName = `test-idb-${++dbCounter}`; engine = new IndexedDBEngine(); await engine.open(dbName, 1); }); afterEach(async () => { if (engine.isOpen()) { await engine.close(); } // 清理:删除 IndexedDB 数据库 try { indexedDB.deleteDatabase(dbName); } catch {} }); // ---- 生命周期 ---- describe('生命周期', () => { it('打开和关闭', async () => { expect(engine.isOpen()).toBe(true); await engine.close(); expect(engine.isOpen()).toBe(false); }); it('未打开时操作抛出错误', async () => { await engine.close(); await expect(engine.count('users')).rejects.toThrow('not opened'); }); it('可以重新打开', async () => { await engine.close(); await engine.open(dbName, 2); expect(engine.isOpen()).toBe(true); }); }); // ---- 表管理 ---- describe('表管理', () => { it('创建和删除表', async () => { await engine.createTable(userSchema); expect(await engine.hasTable('users')).toBe(true); await engine.dropTable('users'); expect(await engine.hasTable('users')).toBe(false); }); it('表名列表', async () => { await engine.createTable(userSchema); const names = await engine.getTableNames(); expect(names).toContain('users'); }); it('获取表结构', async () => { await engine.createTable(userSchema); const schema = await engine.getTableSchema('users'); expect(schema).not.toBeNull(); expect(schema!.name).toBe('users'); }); it('获取不存在的表结构返回 null', async () => { const schema = await engine.getTableSchema('nonexistent'); expect(schema).toBeNull(); }); }); // ---- 插入 ---- describe('插入', () => { beforeEach(async () => { await engine.createTable(userSchema); }); it('插入单行', async () => { const pks = await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'alice@test.com' }, ]); expect(pks).toEqual(['1']); expect(await engine.count('users')).toBe(1); }); it('插入多行', async () => { await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, { id: '2', name: 'Bob', age: 25, email: 'b@t.com' }, ]); expect(await engine.count('users')).toBe(2); }); it('必填字段缺失抛出错误', async () => { await expect( engine.insert('users', [{ id: '1', email: 'a@t.com' }]), ).rejects.toThrow('required'); }); }); // ---- 查询 ---- describe('查询', () => { beforeEach(async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'alice@test.com' }, { id: '2', name: 'Bob', age: 25, email: 'bob@test.com' }, { id: '3', name: 'Charlie', age: 35, email: 'charlie@test.com' }, ]); }); it('查询所有', async () => { const rows = await engine.find('users', { table: 'users' }); expect(rows).toHaveLength(3); }); it('WHERE 条件', async () => { const rows = await engine.find('users', { table: 'users', where: { age: { $gt: 28 } }, }); expect(rows).toHaveLength(2); }); it('ORDER BY + LIMIT', async () => { const rows = await engine.find('users', { table: 'users', orderBy: [{ column: 'age', direction: 'desc' }], limit: 2, }); expect(rows.map(r => r.age)).toEqual([35, 30]); }); it('列选择', async () => { const rows = await engine.find('users', { table: 'users', columns: ['id'], where: { id: '1' }, }); expect(Object.keys(rows[0])).toEqual(['id']); }); }); // ---- 更新 ---- describe('更新', () => { beforeEach(async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, { id: '2', name: 'Bob', age: 25, email: 'b@t.com' }, ]); }); it('更新匹配行', async () => { const count = await engine.update( 'users', { table: 'users', where: { id: '1' } }, { age: 31 }, ); expect(count).toBe(1); const rows = await engine.find('users', { table: 'users', where: { id: '1' } }); expect(rows[0].age).toBe(31); }); it('更新所有行', async () => { const count = await engine.update( 'users', { table: 'users' }, { age: 100 }, ); expect(count).toBe(2); }); }); // ---- 删除 ---- describe('删除', () => { beforeEach(async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, { id: '2', name: 'Bob', age: 25, email: 'b@t.com' }, ]); }); it('条件删除', async () => { const count = await engine.delete('users', { table: 'users', where: { id: '1' }, }); expect(count).toBe(1); expect(await engine.count('users')).toBe(1); }); it('清空表', async () => { await engine.clear('users'); expect(await engine.count('users')).toBe(0); // 表结构仍存在 expect(await engine.hasTable('users')).toBe(true); }); it('删除不存在的表抛出错误', async () => { await expect( engine.delete('nonexistent', { table: 'nonexistent' }), ).rejects.toThrow(); }); }); // ---- Count ---- describe('Count', () => { beforeEach(async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, { id: '2', name: 'Bob', age: 25, email: 'b@t.com' }, ]); }); it('count 全部', async () => { expect(await engine.count('users')).toBe(2); }); it('count with where', async () => { expect(await engine.count('users', { table: 'users', where: { age: { $gt: 28 } }, })).toBe(1); }); }); // ---- 复杂 Where 条件 ---- describe('复杂 Where', () => { beforeEach(async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, { id: '2', name: 'Bob', age: 25, email: 'b@t.com' }, { id: '3', name: 'Charlie', age: 35, email: 'c@t.com' }, ]); }); it('$like 模糊匹配', async () => { const rows = await engine.find('users', { table: 'users', where: { name: { $like: 'A%' } }, }); expect(rows).toHaveLength(1); }); it('$in 列表', async () => { const rows = await engine.find('users', { table: 'users', where: { id: { $in: ['1', '3'] } }, }); expect(rows).toHaveLength(2); }); it('$ne 不等于', async () => { const rows = await engine.find('users', { table: 'users', where: { age: { $ne: 25 } }, }); expect(rows).toHaveLength(2); }); it('$gte $lte 范围', async () => { const rows = await engine.find('users', { table: 'users', where: { age: { $gte: 25, $lte: 30 } }, }); expect(rows).toHaveLength(2); }); }); // ---- 并发/多次操作 ---- describe('多次操作', () => { it('连续创建删除表', async () => { await engine.createTable(userSchema); expect(await engine.hasTable('users')).toBe(true); await engine.dropTable('users'); expect(await engine.hasTable('users')).toBe(false); await engine.createTable(userSchema); expect(await engine.hasTable('users')).toBe(true); }); it('插入后查询再更新再查询', async () => { await engine.createTable(userSchema); await engine.insert('users', [ { id: '1', name: 'Alice', age: 30, email: 'a@t.com' }, ]); let rows = await engine.find('users', { table: 'users' }); expect(rows[0].age).toBe(30); await engine.update('users', { table: 'users' }, { age: 31 }); rows = await engine.find('users', { table: 'users' }); expect(rows[0].age).toBe(31); }); }); });