Files
MetonaSqlark/tests/core.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

291 lines
9.1 KiB
TypeScript

/**
* MetonaSqlark 核心集成测试
*/
import { MetonaSqlark } from '../src/core';
let diskCounter = 0;
// ===================================================================
// Memory 模式
// ===================================================================
describe('MetonaSqlark Memory 模式', () => {
let db: MetonaSqlark;
beforeEach(async () => {
db = new MetonaSqlark({ name: 'test-db-mem', mode: 'memory' });
await db.init();
});
afterEach(async () => {
await db.close();
});
it('创建数据库并初始化', () => {
expect(db.isReady()).toBe(true);
expect(db.name).toBe('test-db-mem');
expect(db.mode).toBe('memory');
});
it('定义表', async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
age: { type: 'number' },
});
const tables = await db.getTableNames();
expect(tables).toContain('users');
});
describe('Query Builder API', () => {
beforeEach(async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
age: { type: 'number' },
});
});
it('insert + select', async () => {
const table = db.table('users');
await table.insert({ id: '1', name: 'Alice', age: 30 });
await table.insert({ id: '2', name: 'Bob', age: 25 });
const results = await table.select().where({ age: { $gt: 20 } }).execute();
expect(results).toHaveLength(2);
});
it('insertMany', async () => {
const table = db.table('users');
await table.insertMany([
{ id: '1', name: 'Alice', age: 30 },
{ id: '2', name: 'Bob', age: 25 },
]);
const count = await table.count();
expect(count).toBe(2);
});
it('update', async () => {
const table = db.table('users');
await table.insert({ id: '1', name: 'Alice', age: 30 });
const count = await table.update({ age: 31 }).where({ id: '1' }).execute();
expect(count).toBe(1);
const results = await table.select().where({ id: '1' }).execute();
expect(results[0].age).toBe(31);
});
it('delete', async () => {
const table = db.table('users');
await table.insert({ id: '1', name: 'Alice', age: 30 });
const count = await table.delete().where({ id: '1' }).execute();
expect(count).toBe(1);
expect(await table.count()).toBe(0);
});
it('orderBy + limit + offset', async () => {
const table = db.table('users');
await table.insertMany([
{ id: '1', name: 'Alice', age: 30 },
{ id: '2', name: 'Bob', age: 25 },
{ id: '3', name: 'Charlie', age: 35 },
]);
const results = await table.select().orderBy('age', 'desc').limit(2).offset(1).execute();
expect(results).toHaveLength(2);
});
it('dropTable', async () => {
await db.dropTable('users');
const tables = await db.getTableNames();
expect(tables).not.toContain('users');
});
});
describe('SQL API', () => {
beforeEach(async () => {
await db.query('CREATE TABLE users (id STRING PRIMARY KEY, name STRING, age NUMBER)');
});
it('SQL INSERT + SELECT', async () => {
await db.query("INSERT INTO users (id, name, age) VALUES ('1', 'Alice', 30)");
await db.query("INSERT INTO users VALUES ('2', 'Bob', 25)");
const result = await db.query('SELECT * FROM users') as Record<string, unknown>[];
expect(result).toHaveLength(2);
});
it('SQL SELECT WHERE', async () => {
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30)");
await db.query("INSERT INTO users VALUES ('2', 'Bob', 25)");
const result = await db.query("SELECT * FROM users WHERE age > 28") as Record<string, unknown>[];
expect(result).toHaveLength(1);
expect(result[0].name).toBe('Alice');
});
it('SQL UPDATE', async () => {
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30)");
await db.query("UPDATE users SET age = 31 WHERE id = '1'");
const result = await db.query("SELECT * FROM users WHERE id = '1'") as Record<string, unknown>[];
expect(result[0].age).toBe(31);
});
it('SQL DELETE', async () => {
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30)");
await db.query("DELETE FROM users WHERE id = '1'");
const result = await db.query('SELECT * FROM users') as Record<string, unknown>[];
expect(result).toHaveLength(0);
});
it('SQL DROP TABLE', async () => {
await db.query('DROP TABLE users');
const tables = await db.getTableNames();
expect(tables).not.toContain('users');
});
});
describe('事务', () => {
beforeEach(async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
balance: { type: 'number', default: 0 },
});
});
it('事务中执行多个操作', async () => {
await db.transaction(async (trx) => {
await trx.table('users').insert({ id: '1', name: 'Alice', balance: 100 });
await trx.table('users').insert({ id: '2', name: 'Bob', balance: 50 });
});
const table = db.table('users');
expect(await table.count()).toBe(2);
});
});
describe('表管理高级', () => {
beforeEach(async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
});
});
it('getTableNames 返回所有表', async () => {
const names = await db.getTableNames();
expect(names).toContain('users');
});
it('dropTable 后表不再存在', async () => {
await db.dropTable('users');
const names = await db.getTableNames();
expect(names).not.toContain('users');
});
it('Table.getSchema 返回表结构', async () => {
const table = db.table('users');
const schema = await table.getSchema();
expect(schema.name).toBe('users');
expect(schema.columns.id.primaryKey).toBe(true);
});
it('Table.clear 清空数据', async () => {
const table = db.table('users');
await table.insert({ id: '1', name: 'Alice' });
await table.insert({ id: '2', name: 'Bob' });
await table.clear();
expect(await table.count()).toBe(0);
expect(await db.getTableNames()).toContain('users');
});
it('Table.drop 删除表', async () => {
const table = db.table('users');
await table.drop();
const names = await db.getTableNames();
expect(names).not.toContain('users');
});
});
});
// ===================================================================
// Disk 模式
// ===================================================================
describe('MetonaSqlark Disk 模式', () => {
let db: MetonaSqlark;
let dbName: string;
beforeEach(async () => {
dbName = `test-disk-${++diskCounter}`;
db = new MetonaSqlark({ name: dbName, mode: 'disk', diskEngine: 'opfs' });
await db.init();
});
afterEach(async () => {
await db.close();
});
it('创建 disk 模式数据库', () => {
expect(db.isReady()).toBe(true);
expect(db.mode).toBe('disk');
});
it('定义表并插入数据', async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
});
await db.table('users').insert({ id: '1', name: 'Alice' });
const rows = await db.table('users').select().execute();
expect(rows).toHaveLength(1);
});
});
// ===================================================================
// Hybrid 模式
// ===================================================================
describe('MetonaSqlark Hybrid 模式', () => {
let db: MetonaSqlark;
let dbName: string;
beforeEach(async () => {
dbName = `test-hybrid-core-${++diskCounter}`;
db = new MetonaSqlark({ name: dbName, mode: 'hybrid', diskEngine: 'opfs' });
await db.init();
});
afterEach(async () => {
await db.close();
});
it('创建 hybrid 模式数据库', () => {
expect(db.isReady()).toBe(true);
expect(db.mode).toBe('hybrid');
});
it('基本 CRUD', async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
});
const table = db.table('users');
await table.insert({ id: '1', name: 'Alice' });
expect(await table.count()).toBe(1);
await table.update({ name: 'Alice2' }).where({ id: '1' }).execute();
const rows = await table.select().where({ id: '1' }).execute();
expect(rows[0].name).toBe('Alice2');
await table.delete().where({ id: '1' }).execute();
expect(await table.count()).toBe(0);
});
it('SQL 查询', async () => {
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
});
await db.query("INSERT INTO users VALUES ('1', 'Alice')");
const result = await db.query('SELECT * FROM users') as Record<string, unknown>[];
expect(result).toHaveLength(1);
});
});