137 lines
4.6 KiB
TypeScript
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);
|
|
});
|
|
});
|