Files
MetonaSqlark/tests/v040-features.test.ts
T
thzxx 0dba1abf2a test(P0): v0.8.0 验证基座与工程门禁根治
工作流 C-1 / C-3 前半 + 测试代码类型检查。

【故障注入基座】新增 tests/helpers/storage-harness.ts + faulty-backend.ts
- TransactionalFileStore:忠实 OPFS 提交语义(close 才可见)+ 字节级故障注入
  (failNextWrite/Append/Delete、truncateAppendTo 撕裂写、crashPending 真崩溃)
- 删除旧 opfs-mock:读返回内部引用、keepExistingData:false 不截断、close 空实现
  导致"提交前可见"等真实缺陷无法被测出(31 个测试文件迁移至新 harness)
- 删除 aria-opfs-backend 内的第三份重复 mock(含从未被断言使用的 writeCalls 死代码
  与 entry.content.subarray 恒等分支)
- FaultyBackend:包装任意 IStorageBackend 注入故障;crash() 明确区别于 close()
  (后者是优雅停机,会刷完写队列 —— 这正是此前所有"崩溃恢复"测试的真相)
- 16 条基座自测证明注入真的生效(含 close 不能当崩溃的对照组)

【覆盖率口径】jest.config.cjs
- 移除 '!src/**/index.ts'(该 glob 把 AriaEngine 主实现等 15 个实现文件整体
  排除出统计,与 v0.2.6 曾承认过的问题同源),改为只排除纯类型声明文件并附理由
- 新增 coverageThreshold 门禁(此前完全不存在)
- 真实基线:语句 90.66% / 分支 82.94% / 函数 94.36% / 行 93.43%
- 修正 testMatch 使 tests/helpers 下的测试可被发现

【测试代码类型检查】tsconfig.test.json + npm run typecheck:tests
- 修复 103 个测试代码类型错误(此前 babel 剥离类型 + tsconfig 排除 tests,全部隐藏)
- 新增 tests/helpers/assertions.ts:nonNull/decode/rows/object/engineMethod/expectCode
  以断言收窄替代 as any
- 消除 21 个 lint warning(含 v043-hardening 中定义后从未调用的 mockOPFS 死代码)
- parser.test.ts 12 处 toBeDefined() 空断言升级为结构断言(并新增 AND/OR 优先级用例,
  当前红灯,对应总账第 11 项,将在工作流 A 修复)

【版本契约】新增 tests/version-contract.test.ts
- 校验 src VERSION / package.json / dist 三者一致,替代两处硬编码版本字面量

【CI 门禁】.gitea/workflows/ci.yml
- lint 去掉 continue-on-error(此前永远不让 CI 变红)
- 新增 tests 类型检查、--coverage 覆盖率门禁、dist 与源码同步校验
- 版本 0.7.4 升至 0.8.0
2026-09-14 21:03:06 +08:00

390 lines
20 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.4.0 功能扩展测试
* - B-1: 流式查询 queryStream / findStream
* - B-2: 多列 ON 哈希连接
* - B-3: FROM 子查询(派生表)
* - B-4: COUNT(DISTINCT) + NULLS FIRST/LAST
*/
import { MetonaSqlark } from '../src/core';
import { AriaEngine } from '../src/engine/aria/index';
import { resetOPFSMock } from './helpers/storage-harness';
import { engineMethod } from './helpers/assertions';
beforeEach(() => { resetOPFSMock(); });
const uniqueName = (prefix: string): string =>
`${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
describe('[v0.4.0] B-1: 流式查询', () => {
test('Aria findStream 逐行回调 + limit 生效', async () => {
const e = new AriaEngine({ storageBackend: 'memory', walSyncMode: 'full' });
await e.open('stream1', 1);
await e.createTable({ name: 'logs', columns: { id: { type: 'string', primaryKey: true }, level: { type: 'string' } } });
const rows: Record<string, unknown>[] = [];
for (let i = 0; i < 5000; i++) rows.push({ id: `${i}`, level: i % 2 ? 'error' : 'info' });
await e.insert('logs', rows);
let count = 0;
let sum = 0;
const n = await e.findStream('logs', { table: 'logs', where: { level: 'error' }, limit: 100 }, (r) => {
count++;
sum += Number(r.id);
});
expect(n).toBe(100);
expect(count).toBe(100);
expect(sum).toBeGreaterThan(0);
await e.close();
});
test('db.queryStream 端到端(WHERE + 投影)', async () => {
const db = new MetonaSqlark({ name: uniqueName('qs'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, age: { type: 'number' } });
await db.query("INSERT INTO users VALUES ('1', 20), ('2', 30), ('3', 40), ('4', 30)");
const seen: Record<string, unknown>[] = [];
const total = await db.queryStream('SELECT id FROM users WHERE age >= 30', (row) => seen.push(row));
expect(total).toBe(3);
expect(seen.map((r) => r.id).sort()).toEqual(['2', '3', '4']);
await db.close();
});
test('queryStream 对 async 回调回退物化(不吞 Promise', async () => {
const db = new MetonaSqlark({ name: uniqueName('qa'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true } });
await db.query("INSERT INTO t VALUES ('1'), ('2')");
const seen: string[] = [];
const total = await db.queryStream('SELECT * FROM t', async (row) => {
await new Promise((r) => setTimeout(r, 1));
seen.push(String(row.id));
});
expect(total).toBe(2);
expect(seen.sort()).toEqual(['1', '2']);
await db.close();
});
test('queryStream 不支持非 SELECT 语句', async () => {
const db = new MetonaSqlark({ name: uniqueName('qi'), mode: 'memory' });
await db.init();
await expect(db.queryStream('INSERT INTO x VALUES (1)', () => {})).rejects.toThrow('only supports SELECT');
await db.close();
});
test('db.table().stream() 逐行回调', async () => {
const db = new MetonaSqlark({ name: uniqueName('qt'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, v: { type: 'number' } });
await db.query("INSERT INTO t VALUES ('1', 10), ('2', 20), ('3', 30)");
const seen: number[] = [];
const total = await db.table('t').stream((row) => seen.push(Number(row.v)), { where: { v: { $gte: 20 } } });
expect(total).toBe(2);
expect(seen.sort((a, b) => a - b)).toEqual([20, 30]);
await db.close();
});
});
describe('[v0.4.0] B-2: 多列 ON 哈希连接', () => {
test('复合键 INNER JOIN 结果正确', async () => {
const db = new MetonaSqlark({ name: uniqueName('hj'), mode: 'memory' });
await db.init();
await db.defineTable('a', {
id: { type: 'string', primaryKey: true },
tenant: { type: 'string', index: true },
key: { type: 'string' },
});
await db.defineTable('b', {
id: { type: 'string', primaryKey: true },
tenant: { type: 'string', index: true },
key: { type: 'string' },
val: { type: 'number' },
});
await db.query("INSERT INTO a VALUES ('a1', 't1', 'k1'), ('a2', 't2', 'k2'), ('a3', 't1', 'k9')");
await db.query("INSERT INTO b VALUES ('b1', 't1', 'k1', 100), ('b2', 't1', 'k2', 200), ('b3', 't2', 'k2', 300)");
// tenant + key 复合等值连接
const rows = await db.query(
"SELECT a.id AS aid, b.val FROM a INNER JOIN b ON a.tenant = b.tenant AND a.key = b.key",
) as Record<string, unknown>[];
expect(rows.length).toBe(2);
const byAid = Object.fromEntries(rows.map((r) => [r.aid, r['b.val']]));
expect(byAid['a1']).toBe(100); // t1/k1 匹配 b1
expect(byAid['a2']).toBe(300); // t2/k2 匹配 b3t1/k2 的 b2 因 tenant 不同被排除)
expect(byAid['a3']).toBeUndefined(); // t1/k9 无匹配
await db.close();
});
test('复合键 LEFT JOIN 无匹配行置 null', async () => {
const db = new MetonaSqlark({ name: uniqueName('hl'), mode: 'memory' });
await db.init();
await db.defineTable('a', { id: { type: 'string', primaryKey: true }, k1: { type: 'string', index: true }, k2: { type: 'string' } });
await db.defineTable('b', { id: { type: 'string', primaryKey: true }, k1: { type: 'string', index: true }, k2: { type: 'string' }, v: { type: 'number' } });
await db.query("INSERT INTO a VALUES ('a1', 'x', 'y'), ('a2', 'x', 'z')");
await db.query("INSERT INTO b VALUES ('b1', 'x', 'y', 5)");
const rows = await db.query(
"SELECT a.id AS aid, b.v FROM a LEFT JOIN b ON a.k1 = b.k1 AND a.k2 = b.k2",
) as Record<string, unknown>[];
expect(rows.length).toBe(2);
expect(rows.find((r) => r.aid === 'a1')?.['b.v']).toBe(5);
expect(rows.find((r) => r.aid === 'a2')?.['b.v']).toBeNull();
await db.close();
});
});
describe('[v0.4.0] B-3: FROM 子查询(派生表)', () => {
test('FROM (SELECT ...) 派生表 + WHERE + ORDER BY', async () => {
const db = new MetonaSqlark({ name: uniqueName('sub'), mode: 'memory' });
await db.init();
await db.defineTable('emp', {
id: { type: 'string', primaryKey: true },
dept: { type: 'string' },
salary: { type: 'number' },
});
await db.query("INSERT INTO emp VALUES ('1', 'eng', 100), ('2', 'eng', 300), ('3', 'ops', 200)");
const rows = await db.query(
"SELECT dept, total FROM (SELECT dept, SUM(salary) AS total FROM emp GROUP BY dept) AS t WHERE total > 150 ORDER BY total DESC",
) as Record<string, unknown>[];
expect(rows).toEqual([{ dept: 'eng', total: 400 }, { dept: 'ops', total: 200 }]);
await db.close();
});
test('派生表无别名也可用', async () => {
const db = new MetonaSqlark({ name: uniqueName('sub2'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, v: { type: 'number' } });
await db.query("INSERT INTO t VALUES ('1', 1), ('2', 2)");
const rows = await db.query("SELECT v FROM (SELECT * FROM t WHERE v > 1) WHERE v < 10") as Record<string, unknown>[];
expect(rows).toEqual([{ v: 2 }]);
await db.close();
});
});
describe('[v0.4.0] B-4: COUNT(DISTINCT) + NULLS FIRST/LAST', () => {
test('COUNT(DISTINCT col)', async () => {
const db = new MetonaSqlark({ name: uniqueName('cd'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, dept: { type: 'string' } });
await db.query("INSERT INTO t VALUES ('1', 'a'), ('2', 'b'), ('3', 'a'), ('4', 'c')");
const rows = await db.query('SELECT COUNT(DISTINCT dept) AS n FROM t') as Record<string, unknown>[];
expect(rows[0].n).toBe(3);
await db.close();
});
test('SUM(DISTINCT col) 与 GROUP BY 组合', async () => {
const db = new MetonaSqlark({ name: uniqueName('sd'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, g: { type: 'string' }, v: { type: 'number' } });
await db.query("INSERT INTO t VALUES ('1', 'x', 10), ('2', 'x', 10), ('3', 'y', 20)");
const rows = await db.query('SELECT g, SUM(DISTINCT v) AS s FROM t GROUP BY g ORDER BY g') as Record<string, unknown>[];
expect(rows).toEqual([{ g: 'x', s: 10 }, { g: 'y', s: 20 }]);
await db.close();
});
test('NULLS FIRST 排序', async () => {
const db = new MetonaSqlark({ name: uniqueName('nf'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, v: { type: 'number' } });
await db.query("INSERT INTO t VALUES ('1', 10), ('2', NULL), ('3', 20)");
const rows = await db.query('SELECT v FROM t ORDER BY v ASC NULLS FIRST') as Record<string, unknown>[];
expect(rows).toEqual([{ v: null }, { v: 10 }, { v: 20 }]);
await db.close();
});
test('NULLS LAST 排序(降序时 NULL 排最后)', async () => {
const db = new MetonaSqlark({ name: uniqueName('nl'), mode: 'memory' });
await db.init();
await db.defineTable('t', { id: { type: 'string', primaryKey: true }, v: { type: 'number' } });
await db.query("INSERT INTO t VALUES ('1', 10), ('2', NULL), ('3', 20)");
const rows = await db.query('SELECT v FROM t ORDER BY v DESC NULLS LAST') as Record<string, unknown>[];
expect(rows).toEqual([{ v: 20 }, { v: 10 }, { v: null }]);
await db.close();
});
test('字符串常量列 + \'\' 转义(无 FROM 查询)', async () => {
const db = new MetonaSqlark({ name: uniqueName('lit'), mode: 'memory' });
await db.init();
const rows = await db.query("SELECT 'it''s a test' AS escaped") as Record<string, unknown>[];
expect(rows).toEqual([{ escaped: "it's a test" }]);
const mixed = await db.query("SELECT 'hello' AS greeting, 'world' AS subject") as Record<string, unknown>[];
expect(mixed).toEqual([{ greeting: 'hello', subject: 'world' }]);
await db.close();
});
test('ORDER BY / GROUP BY 支持表前缀列(u.name / o.amount', async () => {
const db = new MetonaSqlark({ name: uniqueName('prefix'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string' }, age: { type: 'number' } });
await db.defineTable('orders', { id: { type: 'string', primaryKey: true }, user_id: { type: 'string' }, amount: { type: 'number' } });
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30), ('2', 'Bob', 25)");
await db.query("INSERT INTO orders VALUES ('o1', '1', 1200), ('o2', '2', 50)");
// JOIN + ORDER BY 表前缀(演示页报错场景)
const join = await db.query(
'SELECT u.name, o.amount FROM users u INNER JOIN orders o ON u.id = o.user_id ORDER BY o.amount DESC',
) as Record<string, unknown>[];
expect(join.map((r) => r['u.name'])).toEqual(['Alice', 'Bob']);
// JOIN + GROUP BY 表前缀
const grouped = await db.query(
'SELECT u.name, SUM(o.amount) AS total FROM users u INNER JOIN orders o ON u.id = o.user_id GROUP BY u.name',
) as Record<string, unknown>[];
expect(grouped.map((r) => r.total).sort((a, b) => Number(b) - Number(a))).toEqual([1200, 50]);
// 非 JOIN + ORDER BY / GROUP BY 表前缀
const plain = await db.query('SELECT name FROM users ORDER BY users.age DESC') as Record<string, unknown>[];
expect(plain.map((r) => r.name)).toEqual(['Alice', 'Bob']);
const byAge = await db.query('SELECT users.age, COUNT(*) AS n FROM users GROUP BY users.age') as Record<string, unknown>[];
expect(byAge.length).toBe(2);
await db.close();
});
test('INSERT ... SELECT 按源表列顺序映射(缺列不填,不报类型错)', async () => {
const db = new MetonaSqlark({ name: uniqueName('insel'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string', required: true }, email: { type: 'string' }, age: { type: 'number', default: 0 } });
await db.table('users').insertMany([{ id: '1', name: 'Alice', email: 'a@x.com', age: 30 }]);
// alter 预设:ADD 列 → 显式列名插入(无 email)→ DROP 列,产生行键缺 email 的行
await db.query('ALTER TABLE users ADD COLUMN phone STRING');
await db.query("INSERT INTO users (id, name, age, phone) VALUES ('6', 'Frank', 33, '123')");
await db.query('ALTER TABLE users DROP COLUMN phone');
await db.query('CREATE TABLE users_backup (id STRING PRIMARY KEY, name STRING, email STRING, age NUMBER)');
await db.query('INSERT INTO users_backup SELECT * FROM users');
const rows = await db.query('SELECT * FROM users_backup ORDER BY id') as Record<string, unknown>[];
expect(rows).toHaveLength(2);
expect(rows[0]).toEqual({ id: '1', name: 'Alice', email: 'a@x.com', age: 30 });
expect(rows[1].id).toBe('6');
expect(rows[1].name).toBe('Frank');
expect(rows[1].age).toBe(33);
// SELECT 指定列映射
await db.query('CREATE TABLE names_only (id STRING PRIMARY KEY, name STRING)');
await db.query('INSERT INTO names_only SELECT id, name FROM users');
const names = await db.query('SELECT * FROM names_only') as Record<string, unknown>[];
expect(names.map((r) => r.name).sort()).toEqual(['Alice', 'Frank']);
await db.close();
});
test('关联 EXISTS / NOT EXISTSSELECT 列仅含 name 时绑定主键仍生效)', async () => {
const db = new MetonaSqlark({ name: uniqueName('exists'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string' }, age: { type: 'number' } });
await db.defineTable('orders', { id: { type: 'string', primaryKey: true }, user_id: { type: 'string' }, amount: { type: 'number' } });
await db.query("INSERT INTO users VALUES ('1', 'Alice', 30), ('2', 'Bob', 25), ('3', 'Eve', 22)");
await db.query("INSERT INTO orders VALUES ('o1', '1', 100), ('o2', '1', 200), ('o3', '2', 50)");
// SELECT 只投影 name(不含 id),EXISTS 绑定 u.id 必须仍工作
const withOrders = await db.query(
'SELECT u.name FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)',
) as Record<string, unknown>[];
expect(withOrders.map((r) => r.name).sort()).toEqual(['Alice', 'Bob']);
const without = await db.query(
'SELECT u.name FROM users u WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)',
) as Record<string, unknown>[];
expect(without.map((r) => r.name)).toEqual(['Eve']);
// SELECT 列带表前缀 + EXISTS 组合
const prefixed = await db.query(
'SELECT u.name FROM users u WHERE u.age > 21 AND EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id)',
) as Record<string, unknown>[];
expect(prefixed.map((r) => r.name).sort()).toEqual(['Alice', 'Bob']);
await db.close();
});
test('HAVING 引用聚合表达式 + 标量子查询', async () => {
const db = new MetonaSqlark({ name: uniqueName('having'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string' } });
await db.defineTable('orders', { id: { type: 'string', primaryKey: true }, user_id: { type: 'string' }, amount: { type: 'number' } });
await db.query("INSERT INTO users VALUES ('1', 'Alice'), ('2', 'Bob'), ('3', 'Charlie')");
await db.query("INSERT INTO orders VALUES ('o1', '1', 1200), ('o2', '1', 50), ('o3', '2', 150), ('o4', '3', 400), ('o5', '3', 20)");
// HAVING SUM(...) > (SELECT AVG(...)):均值 364Alice 1250 / Charlie 420 达标
const rows = await db.query(
'SELECT u.name, SUM(o.amount) AS spent FROM users u INNER JOIN orders o ON u.id = o.user_id GROUP BY u.name HAVING SUM(o.amount) > (SELECT AVG(amount) FROM orders)',
) as Record<string, unknown>[];
expect(rows.map((r) => [r['u.name'], r.spent])).toEqual([['Alice', 1250], ['Charlie', 420]]);
// HAVING 引用别名也生效
const byAlias = await db.query(
'SELECT u.name, SUM(o.amount) AS spent FROM users u INNER JOIN orders o ON u.id = o.user_id GROUP BY u.name HAVING spent > 400',
) as Record<string, unknown>[];
expect(byAlias.map((r) => r['u.name']).sort()).toEqual(['Alice', 'Charlie']);
await db.close();
});
test('JOIN 主表 WHERE 条件下推走索引 + DROP INDEX 报错', async () => {
const db = new MetonaSqlark({ name: uniqueName('idx'), mode: 'memory' });
await db.init();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string' } });
await db.defineTable('orders', { id: { type: 'string', primaryKey: true }, user_id: { type: 'string' }, product: { type: 'string' } });
await db.query("INSERT INTO users VALUES ('1', 'Alice'), ('2', 'Bob')");
await db.query("INSERT INTO orders VALUES ('o1', '1', 'Laptop'), ('o2', '1', 'Mouse'), ('o3', '2', 'Keyboard')");
await db.query('CREATE INDEX idx_orders_user ON orders (user_id)');
// WHERE 主表前缀条件下推:引擎收到的 orders 查询 where 为 { user_id: { $eq: '1' } }
const eng = db.getEngine() as { find?: (...a: unknown[]) => Promise<unknown> };
if (!eng.find) throw new Error('engine.find is required for this probe');
const engineFind = eng.find;
const origFind = engineFind.bind(eng) as (...a: unknown[]) => Promise<unknown>;
let pushed: unknown = null;
eng.find = async (...args: unknown[]): Promise<unknown> => {
const [t, q] = args as [string, { where?: unknown } | undefined];
if (t === 'orders' && q?.where) pushed = q.where;
return origFind(...args);
};
const rows = await db.query(
"SELECT u.name, o.product FROM orders o JOIN users u ON u.id = o.user_id WHERE o.user_id = '1'",
) as Record<string, unknown>[];
expect(rows.map((r) => [r['u.name'], r['o.product']])).toEqual([['Alice', 'Laptop'], ['Alice', 'Mouse']]);
expect(pushed).toEqual({ user_id: { $eq: '1' } });
// DROP 存在的索引成功;再次 DROP(列已无索引)报 INDEX_NOT_FOUND
await db.query('DROP INDEX idx_orders_user ON orders (user_id)');
await expect(db.query('DROP INDEX idx_nonexist ON orders (user_id)')).rejects.toThrow('Index on column');
// DROP 后回退全表扫描,结果不变
const after = await db.query("SELECT product FROM orders WHERE user_id = '2'") as Record<string, unknown>[];
expect(after.map((r) => r.product)).toEqual(['Keyboard']);
await db.close();
});
test('裸布尔列条件:WHERE done / CASE WHEN done(真值判断)', async () => {
const db = new MetonaSqlark({ name: uniqueName('bool'), mode: 'memory' });
await db.init();
await db.defineTable('tasks', { id: { type: 'string', primaryKey: true }, title: { type: 'string' }, done: { type: 'boolean', default: false } });
await db.query("INSERT INTO tasks VALUES ('t1', 'A', false), ('t2', 'B', true), ('t3', 'C', false)");
// WHERE 裸列
const done = await db.query('SELECT id FROM tasks WHERE done') as Record<string, unknown>[];
expect(done.map((r) => r.id)).toEqual(['t2']);
// CASE WHEN 裸列(演示页 aria 预设)
const labeled = await db.query(
"SELECT title, CASE WHEN done THEN 'done' ELSE 'pending' END AS status FROM tasks",
) as Record<string, unknown>[];
expect(labeled.find((r) => r.title === 'B')?.status).toBe('done');
expect(labeled.find((r) => r.title === 'A')?.status).toBe('pending');
await db.close();
});
test('Aria $in 查询去重(IN 子查询含重复值不返回重复行)', async () => {
const db = new MetonaSqlark({ name: uniqueName('indup'), mode: 'aria', diskEngine: 'opfs' });
await db.init();
await engineMethod<() => Promise<void>>(db.getEngine(), 'clearAll')();
await db.defineTable('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string' } });
await db.defineTable('orders', { id: { type: 'string', primaryKey: true }, user_id: { type: 'string' } });
await db.query("INSERT INTO users VALUES ('1', 'Alice'), ('2', 'Bob')");
await db.query("INSERT INTO orders VALUES ('o1', '1'), ('o2', '1')");
const rows = await db.query('SELECT name FROM users WHERE id IN (SELECT user_id FROM orders)') as Record<string, unknown>[];
expect(rows).toHaveLength(1);
expect(rows[0].name).toBe('Alice');
await db.close();
});
});