/** * QueryBuilder 和 Compiler/Executor 测试 */ import { MemoryEngine } from '../../src/engine/memory'; import { createSchema } from '../../src/table/schema'; import { SelectQueryBuilder, UpdateQueryBuilder, DeleteQueryBuilder } from '../../src/query/builder'; import { compileStatement } from '../../src/query/compiler'; import { QueryExecutor } from '../../src/query/executor'; import { parse } from '../../src/sql/parser'; describe('QueryBuilder', () => { let engine: MemoryEngine; beforeEach(async () => { engine = new MemoryEngine(); await engine.open('test-qb', 1); }); afterEach(async () => { await engine.close(); }); // ---- SelectQueryBuilder ---- describe('SelectQueryBuilder', () => { it('基础查询', () => { const qb = new SelectQueryBuilder(engine, 'users'); expect(qb.toAST()).toMatchObject({ type: 'SELECT', columns: ['*'], from: 'users', where: {}, }); }); it('链式调用', () => { const qb = new SelectQueryBuilder(engine, 'users', ['id', 'name']); qb.where({ age: { $gt: 18 } }).orderBy('name', 'asc').limit(10).offset(5); const ast = qb.toAST(); expect(ast.columns).toEqual(['id', 'name']); expect(ast.where).toEqual({ age: { $gt: 18 } }); expect(ast.orderBy).toEqual([{ column: 'name', direction: 'asc' }]); expect(ast.limit).toBe(10); expect(ast.offset).toBe(5); }); it('多次 where 合并条件', () => { const qb = new SelectQueryBuilder(engine, 'users'); qb.where({ age: { $gt: 18 } }).where({ active: true }); expect(qb.toAST().where).toEqual({ age: { $gt: 18 }, active: true }); }); it('多次 orderBy 追加排序', () => { const qb = new SelectQueryBuilder(engine, 'users'); qb.orderBy('age', 'desc').orderBy('name', 'asc'); expect(qb.toAST().orderBy).toHaveLength(2); }); }); // ---- UpdateQueryBuilder ---- describe('UpdateQueryBuilder', () => { it('基础更新', () => { const qb = new UpdateQueryBuilder(engine, 'users', { age: 31 }); qb.where({ id: '1' }); const ast = qb.toAST(); expect(ast).toMatchObject({ type: 'UPDATE', table: 'users', sets: { age: 31 }, where: { id: '1' }, }); }); it('不带 where', () => { const qb = new UpdateQueryBuilder(engine, 'users', { active: false }); expect(qb.toAST().where).toEqual({}); }); }); // ---- DeleteQueryBuilder ---- describe('DeleteQueryBuilder', () => { it('基础删除', () => { const qb = new DeleteQueryBuilder(engine, 'users'); qb.where({ id: '1' }); const ast = qb.toAST(); expect(ast).toMatchObject({ type: 'DELETE', from: 'users', where: { id: '1' }, }); }); it('不带 where', () => { const qb = new DeleteQueryBuilder(engine, 'users'); expect(qb.toAST().where).toEqual({}); }); }); }); // =================================================================== describe('Compiler', () => { it('编译 SELECT', () => { const ast = parse('SELECT id, name FROM users WHERE age > 18 ORDER BY age DESC LIMIT 10'); const plan = compileStatement(ast); expect(plan.table).toBe('users'); expect(plan.columns).toEqual(['id', 'name']); expect(plan.where).toBeDefined(); expect(plan.orderBy).toEqual([{ column: 'age', direction: 'desc' }]); expect(plan.limit).toBe(10); }); it('编译 DELETE', () => { const ast = parse("DELETE FROM users WHERE id = '1'"); const plan = compileStatement(ast); expect(plan.table).toBe('users'); expect(plan.where).toBeDefined(); }); it('编译 UPDATE', () => { const ast = parse("UPDATE users SET age = 31 WHERE id = '1'"); const plan = compileStatement(ast); expect(plan.table).toBe('users'); expect(plan.where).toBeDefined(); }); it('非查询语句抛出错误', () => { const ast = parse('CREATE TABLE users (id STRING PRIMARY KEY)'); expect(() => compileStatement(ast)).toThrow('Cannot compile'); }); }); // =================================================================== describe('QueryExecutor', () => { let engine: MemoryEngine; let executor: QueryExecutor; beforeEach(async () => { engine = new MemoryEngine(); await engine.open('test-exec', 1); executor = new QueryExecutor(engine); }); afterEach(async () => { await engine.close(); }); it('执行 CREATE TABLE', async () => { const ast = parse('CREATE TABLE users (id STRING PRIMARY KEY, name STRING)'); await executor.execute(ast); expect(await engine.hasTable('users')).toBe(true); }); it('执行 INSERT + SELECT', async () => { await executor.execute(parse('CREATE TABLE users (id STRING PRIMARY KEY, name STRING, age NUMBER)')); await executor.execute(parse("INSERT INTO users (id, name, age) VALUES ('1', 'Alice', 30)")); await executor.execute(parse("INSERT INTO users VALUES ('2', 'Bob', 25)")); const result = await executor.execute(parse('SELECT * FROM users')) as Record[]; expect(result).toHaveLength(2); }); it('执行 UPDATE', async () => { await executor.execute(parse('CREATE TABLE users (id STRING PRIMARY KEY, name STRING, age NUMBER)')); await executor.execute(parse("INSERT INTO users VALUES ('1', 'Alice', 30)")); await executor.execute(parse("UPDATE users SET age = 31 WHERE id = '1'")); const result = await executor.execute(parse("SELECT * FROM users WHERE id = '1'")) as Record[]; expect(result[0].age).toBe(31); }); it('执行 DELETE', async () => { await executor.execute(parse('CREATE TABLE users (id STRING PRIMARY KEY, name STRING)')); await executor.execute(parse("INSERT INTO users VALUES ('1', 'Alice')")); await executor.execute(parse("INSERT INTO users VALUES ('2', 'Bob')")); await executor.execute(parse("DELETE FROM users WHERE id = '1'")); const result = await executor.execute(parse('SELECT * FROM users')) as Record[]; expect(result).toHaveLength(1); }); it('执行 DROP TABLE', async () => { await executor.execute(parse('CREATE TABLE users (id STRING PRIMARY KEY)')); await executor.execute(parse('DROP TABLE users')); expect(await engine.hasTable('users')).toBe(false); }); it('操作不存在的表抛出错误', async () => { await expect( executor.execute(parse('SELECT * FROM nonexistent')), ).rejects.toThrow('does not exist'); }); it('getEngine', () => { expect(executor.getEngine()).toBe(engine); }); });