Files
MetonaSqlark/tests/hooks-crud.test.ts
T
thzxx 24b3ca1079
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
release: v0.6.0 — 完全移除 IndexedDB,自研 KVStore 事务存储引擎(多key原子写/快照日志恢复/CRC自愈)+ KVStoreEngine + 旧库迁移工具 + 10万级压力验证 + 崩溃注入e2e
2026-08-10 13:56:04 +08:00

140 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* v0.5.1 — CRUD 生命周期钩子真实接线测试
*
* 此前 beforeInsert/afterInsert/beforeUpdate/afterUpdate/beforeDelete/afterDelete
* 六个钩子虽在 HookName 类型与文档中宣称("14 种钩子"),但从未被任何路径触发。
* 本次验证 Table API 与 SQL query 两条路径均真实触发全部 14 个钩子。
*/
import { MetonaSqlark } from '../src/core';
async function createDb(name: string): Promise<MetonaSqlark> {
const db = new MetonaSqlark({ name: `hooks-${name}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, mode: 'memory' });
await db.init();
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string' },
age: { type: 'number' },
});
return db;
}
describe('v0.5.1 — CRUD hooks 真实接线', () => {
it('Table.insert / insertMany 触发 beforeInsert + afterInsert', async () => {
const db = await createDb('table-insert');
const events: string[] = [];
db.on('beforeInsert', (rows) => { events.push(`before:${(rows as unknown[]).length}`); });
db.on('afterInsert', (rows, pks) => { events.push(`after:${(rows as unknown[]).length}:${(pks as string[]).length}`); });
await db.table('users').insert({ id: '1', name: 'A' });
await db.table('users').insertMany([{ id: '2', name: 'B' }, { id: '3', name: 'C' }]);
expect(events).toEqual([
'before:1', 'after:1:1',
'before:2', 'after:2:2',
]);
await db.close();
});
it('Table.update().execute() 触发 beforeUpdate + afterUpdate(含影响行数)', async () => {
const db = await createDb('table-update');
await db.table('users').insertMany([{ id: '1', name: 'A', age: 1 }, { id: '2', name: 'B', age: 2 }]);
const events: string[] = [];
db.on('beforeUpdate', (query, updates) => { events.push(`before:${(updates as Record<string, unknown>).name}`); });
db.on('afterUpdate', (_query, _updates, count) => { events.push(`after:${count}`); });
await db.table('users').update({ name: 'X' }).where({ age: { $gt: 1 } }).execute();
expect(events).toEqual(['before:X', 'after:1']);
await db.close();
});
it('Table.delete().execute() 触发 beforeDelete + afterDelete(含影响行数)', async () => {
const db = await createDb('table-delete');
await db.table('users').insertMany([{ id: '1', name: 'A' }, { id: '2', name: 'B' }]);
const events: string[] = [];
db.on('beforeDelete', (query) => { events.push(`before:${(query as { where: Record<string, unknown> }).where.id}`); });
db.on('afterDelete', (_query, count) => { events.push(`after:${count}`); });
await db.table('users').delete().where({ id: '1' }).execute();
expect(events).toEqual(['before:1', 'after:1']);
await db.close();
});
it('SQL query 路径触发全部 CRUD hooksINSERT/UPDATE/DELETE', async () => {
const db = await createDb('sql-crud');
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30)");
const events: string[] = [];
db.on('beforeInsert', () => events.push('beforeInsert'));
db.on('afterInsert', () => events.push('afterInsert'));
db.on('beforeUpdate', () => events.push('beforeUpdate'));
db.on('afterUpdate', () => events.push('afterUpdate'));
db.on('beforeDelete', () => events.push('beforeDelete'));
db.on('afterDelete', () => events.push('afterDelete'));
await db.query("INSERT INTO users VALUES ('2', 'Bob', 25)");
await db.query("UPDATE users SET age = 26 WHERE id = '2'");
await db.query("DELETE FROM users WHERE id = '1'");
expect(events).toEqual([
'beforeInsert', 'afterInsert',
'beforeUpdate', 'afterUpdate',
'beforeDelete', 'afterDelete',
]);
await db.close();
});
it('SQL INSERT 多行语句按列名映射触发 afterInsert', async () => {
const db = await createDb('sql-insert-cols');
const seen: unknown[] = [];
db.on('afterInsert', (_rows, pks) => seen.push(pks));
await db.query("INSERT INTO users (id, name) VALUES ('9', 'Zed')");
expect(seen).toEqual([['9']]);
await db.close();
});
it('全部 14 个钩子均可注册并真实触发', async () => {
const db = await createDb('all-hooks');
const fired = new Set<string>();
const hooks = [
'beforeCreateTable', 'afterCreateTable',
'beforeDropTable', 'afterDropTable',
'beforeInsert', 'afterInsert',
'beforeUpdate', 'afterUpdate',
'beforeDelete', 'afterDelete',
'beforeQuery', 'afterQuery',
'beforeTransaction', 'afterTransaction',
] as const;
for (const h of hooks) db.on(h, () => fired.add(h));
await db.defineTable('t2', { id: { type: 'string', primaryKey: true } }); // createTable hooks
await db.table('t2').insert({ id: '1' }); // insert hooks
await db.table('t2').update({}).where({ id: '1' }).execute(); // update hooks
await db.table('t2').delete().where({ id: '1' }).execute(); // delete hooks
await db.query('SELECT * FROM t2'); // query hooks
await db.transaction(async () => { /* noop */ }); // transaction hooks
await db.dropTable('t2'); // dropTable hooks
for (const h of hooks) {
expect(fired.has(h)).toBe(true);
if (!fired.has(h)) throw new Error(`hook ${h} 应被触发`);
}
await db.close();
});
it('事务路径不触发 CRUD hooksTable 无 hooks 回调)', async () => {
const db = await createDb('tx-hooks');
let fired = false;
db.on('beforeInsert', () => { fired = true; });
await db.transaction(async (trx) => {
await trx.table('users').insert({ id: '1', name: 'Tx' });
});
expect(fired).toBe(false);
await db.close();
});
});