Files
MetonaSqlark/tests/subquery.test.ts
T
thzxx 71e238a5cc
CI / test (18.x) (push) Successful in 9m52s
CI / test (20.x) (push) Successful in 9m50s
CI / test (22.x) (push) Successful in 9m51s
CI / test (24.x) (push) Successful in 9m49s
test: v0.1.13 新增42项测试覆盖(事务回滚/子查询/外键级联/连接池)
2026-07-26 16:40:11 +08:00

137 lines
4.6 KiB
TypeScript

/**
* v0.1.13 子查询测试
* 覆盖 SQL Parser 子查询解析 + Executor 子查询执行
*/
import { MetonaSqlark } from '../src/core';
import { parse } from '../src/sql/parser';
// ===================================================================
// SQL 子查询解析
// ===================================================================
describe('v0.1.13 子查询 — Parser', () => {
it('IN 子查询解析', () => {
const stmt = parse('SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)');
expect(stmt.type).toBe('SELECT');
});
it('NOT IN 子查询解析', () => {
const stmt = parse('SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders)');
expect(stmt.type).toBe('SELECT');
});
it('标量子查询解析 (eq)', () => {
const stmt = parse('SELECT * FROM users WHERE age = (SELECT AVG(age) FROM users)');
expect(stmt.type).toBe('SELECT');
});
it('标量子查询解析 (gt)', () => {
const stmt = parse('SELECT * FROM users WHERE age > (SELECT AVG(age) FROM users)');
expect(stmt.type).toBe('SELECT');
});
it('子查询带 WHERE', () => {
const stmt = parse("SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100)");
expect(stmt.type).toBe('SELECT');
});
it('子查询带 JOIN', () => {
const stmt = parse(`SELECT * FROM users u
WHERE u.id IN (SELECT o.user_id FROM orders o INNER JOIN products p ON o.product = p.name)`);
expect(stmt.type).toBe('SELECT');
});
});
// ===================================================================
// 子查询执行
// ===================================================================
describe('v0.1.13 子查询 — Executor', () => {
let db: MetonaSqlark;
beforeEach(async () => {
db = new MetonaSqlark({ name: 'subquery-test', mode: 'memory' });
await db.init();
await db.defineTable('users', {
id: { type: 'string', primaryKey: true },
name: { type: 'string', required: true },
age: { type: 'number', default: 0 },
});
await db.defineTable('orders', {
id: { type: 'string', primaryKey: true },
user_id: { type: 'string' },
amount: { type: 'number' },
});
// Seed data
await db.table('users').insertMany([
{ id: '1', name: 'Alice', age: 30 },
{ id: '2', name: 'Bob', age: 25 },
{ id: '3', name: 'Charlie', age: 35 },
{ id: '4', name: 'Diana', age: 20 },
]);
await db.table('orders').insertMany([
{ id: 'o1', user_id: '1', amount: 100 },
{ id: 'o2', user_id: '1', amount: 200 },
{ id: 'o3', user_id: '2', amount: 50 },
]);
});
afterEach(async () => { await db.close(); });
it('IN 子查询: 有订单的用户', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)"
) as Record<string, unknown>[];
expect(rows).toHaveLength(2); // Alice + Bob
const names = rows.map((r) => r.name);
expect(names).toContain('Alice');
expect(names).toContain('Bob');
});
it('NOT IN 子查询: 无订单的用户', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders)"
) as Record<string, unknown>[];
expect(rows).toHaveLength(2); // Charlie + Diana
const names = rows.map((r) => r.name);
expect(names).toContain('Charlie');
expect(names).toContain('Diana');
});
it('IN 子查询 + WHERE 过滤', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100)"
) as Record<string, unknown>[];
expect(rows).toHaveLength(1); // 只有 Alice 有 >100 订单
expect(rows[0].name).toBe('Alice');
});
it('标量子查询: 年龄大于平均值的用户', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE age > (SELECT AVG(age) FROM users)"
) as Record<string, unknown>[];
// AVG = (30+25+35+20)/4 = 27.5 → age > 27.5: Alice(30), Charlie(35)
expect(rows).toHaveLength(2);
const names = rows.map((r) => r.name);
expect(names).toContain('Alice');
expect(names).toContain('Charlie');
});
it('标量子查询: 年龄等于最大值的用户', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE age = (SELECT MAX(age) FROM users)"
) as Record<string, unknown>[];
expect(rows).toHaveLength(1);
expect(rows[0].name).toBe('Charlie');
});
it('空子查询结果处理', async () => {
const rows = await db.query(
"SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 9999)"
) as Record<string, unknown>[];
expect(rows).toHaveLength(0);
});
});