69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
import { Database } from 'bun:sqlite';
|
|
import {
|
|
ensureFinancialIngestionSchemaHealthy,
|
|
inspectFinancialIngestionSchema,
|
|
resolveFinancialSchemaRepairMode
|
|
} from '../lib/server/db/financial-ingestion-schema';
|
|
import { resolveSqlitePath } from './dev-env';
|
|
|
|
function parseArgs(argv: string[]) {
|
|
const flags = new Set(argv);
|
|
|
|
return {
|
|
dryRun: flags.has('--dry-run'),
|
|
verbose: flags.has('--verbose'),
|
|
failOnDrift: flags.has('--fail-on-drift')
|
|
};
|
|
}
|
|
|
|
function resolveDatabasePath() {
|
|
const raw = process.env.DATABASE_URL?.trim() || 'file:data/fiscal.sqlite';
|
|
const databasePath = resolveSqlitePath(raw);
|
|
|
|
if (!databasePath || databasePath.includes('://')) {
|
|
throw new Error(`DATABASE_URL must resolve to a SQLite file path. Received: ${raw}`);
|
|
}
|
|
|
|
return databasePath;
|
|
}
|
|
|
|
const options = parseArgs(process.argv.slice(2));
|
|
const databasePath = resolveDatabasePath();
|
|
const client = new Database(databasePath, { create: true });
|
|
|
|
try {
|
|
client.exec('PRAGMA foreign_keys = ON;');
|
|
|
|
const mode = options.dryRun
|
|
? 'check-only'
|
|
: resolveFinancialSchemaRepairMode(process.env.FINANCIAL_SCHEMA_REPAIR_MODE);
|
|
const before = inspectFinancialIngestionSchema(client);
|
|
const result = ensureFinancialIngestionSchemaHealthy(client, { mode });
|
|
|
|
console.info(`[repair-financial-ingestion-schema] db=${databasePath}`);
|
|
console.info(`[repair-financial-ingestion-schema] mode=${mode}`);
|
|
console.info(`[repair-financial-ingestion-schema] status=${result.mode}`);
|
|
console.info(`[repair-financial-ingestion-schema] missing_indexes_before=${before.missingIndexes.join(',') || 'none'}`);
|
|
console.info(`[repair-financial-ingestion-schema] duplicate_groups_before=${before.duplicateGroups}`);
|
|
|
|
if (result.repair) {
|
|
console.info(`[repair-financial-ingestion-schema] indexes_created=${result.repair.indexesCreated.join(',') || 'none'}`);
|
|
console.info(`[repair-financial-ingestion-schema] indexes_recreated=${result.repair.indexesRecreated.join(',') || 'none'}`);
|
|
console.info(`[repair-financial-ingestion-schema] duplicate_rows_deleted=${result.repair.duplicateRowsDeleted}`);
|
|
console.info(`[repair-financial-ingestion-schema] bundle_cache_cleared=${result.repair.bundleCacheCleared ? 'yes' : 'no'}`);
|
|
}
|
|
|
|
if (options.verbose) {
|
|
console.info(JSON.stringify({
|
|
before,
|
|
after: result
|
|
}, null, 2));
|
|
}
|
|
|
|
if (options.failOnDrift && !result.ok) {
|
|
process.exit(1);
|
|
}
|
|
} finally {
|
|
client.close();
|
|
}
|