73 lines
2.8 KiB
TypeScript
73 lines
2.8 KiB
TypeScript
import { afterEach, beforeEach, expect, it, vi } from 'vitest';
|
|
import { newFixture, type Fixture } from '../helpers/fixture.js';
|
|
|
|
let fixture: Fixture;
|
|
beforeEach(async () => {
|
|
vi.resetModules();
|
|
fixture = await newFixture([]);
|
|
});
|
|
afterEach(async () => {
|
|
await fixture.cleanup();
|
|
});
|
|
|
|
it('indexes campaign cascades and beta evidence on fresh and reopened databases', async () => {
|
|
const { db, closeDb } = await import('../../src/lib/server/db/index.js');
|
|
for (let pass = 0; pass < 2; pass++) {
|
|
const handle = db();
|
|
for (const [query, index] of [
|
|
[
|
|
'SELECT id FROM staged_file_changes WHERE deployment_file_id = 1',
|
|
'idx_staged_files_deployment_file'
|
|
],
|
|
[
|
|
'SELECT id FROM beta_test_runs WHERE beta_id = 1 AND revision = 2',
|
|
'idx_beta_test_runs_beta_revision'
|
|
]
|
|
]) {
|
|
const plan = handle.prepare(`EXPLAIN QUERY PLAN ${query}`).all() as {
|
|
detail: string;
|
|
}[];
|
|
expect(plan.some((row) => row.detail.includes(index))).toBe(true);
|
|
}
|
|
expect(handle.pragma('foreign_key_check')).toEqual([]);
|
|
closeDb();
|
|
}
|
|
});
|
|
|
|
it('covers every foreign key child prefix, including lazy host and library schemas', async () => {
|
|
const { db } = await import('../../src/lib/server/db/index.js');
|
|
const { ensureHostSchema } = await import('../../src/lib/server/hosts/schema.js');
|
|
const { ensureGameFileSchema } = await import('../../src/lib/server/game-files/schema.js');
|
|
const handle = db();
|
|
ensureHostSchema(handle);
|
|
ensureGameFileSchema(handle);
|
|
const tables = handle.prepare("SELECT name FROM sqlite_master WHERE type='table'").all() as {
|
|
name: string;
|
|
}[];
|
|
const missing: string[] = [];
|
|
for (const { name } of tables) {
|
|
const foreignKeys = handle.pragma(`foreign_key_list(${name})`) as {
|
|
from: string;
|
|
seq: number;
|
|
}[];
|
|
const indexes = handle.pragma(`index_list(${name})`) as { name: string; partial: number }[];
|
|
const prefixes = indexes
|
|
.filter((index) => !index.partial)
|
|
.map(
|
|
(index) =>
|
|
(handle.pragma(`index_info(${index.name})`) as { name: string }[])[0]?.name
|
|
);
|
|
const columns = handle.pragma(`table_info(${name})`) as {
|
|
name: string;
|
|
type: string;
|
|
pk: number;
|
|
}[];
|
|
if (columns.filter((column) => column.pk).length === 1)
|
|
prefixes.push(columns.find((column) => column.pk)!.name);
|
|
for (const key of foreignKeys.filter((key) => key.seq === 0)) {
|
|
if (!prefixes.includes(key.from)) missing.push(`${name}.${key.from}`);
|
|
}
|
|
}
|
|
expect(missing).toEqual([]);
|
|
});
|