46 lines
2.2 KiB
TypeScript
46 lines
2.2 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
|
|
/** Keep metadata ahead of overflow pages, preserving IDs and all references. */
|
|
export function migrateVersionLayout(handle: Database.Database): void {
|
|
const columns = handle.pragma('table_info(script_versions)') as { name: string }[];
|
|
if (!columns.some((column) => column.name === 'content') || columns.at(-1)?.name === 'content')
|
|
return;
|
|
const { sql } = handle
|
|
.prepare("SELECT sql FROM sqlite_master WHERE name='script_versions'")
|
|
.get() as { sql: string };
|
|
const content = /\bcontent\s+BLOB\s+NOT\s+NULL\s*,/i;
|
|
if (!content.test(sql)) throw new Error('Unrecognized script version content layout');
|
|
const replacement = sql
|
|
.replace(content, '')
|
|
.replace(/,\s*UNIQUE\s*\(/i, ', content BLOB NOT NULL, UNIQUE(')
|
|
.replace('script_versions', 'script_versions_metadata');
|
|
const dependents = handle
|
|
.prepare(
|
|
"SELECT sql FROM sqlite_master WHERE tbl_name='script_versions' AND type IN ('index','trigger') AND sql IS NOT NULL"
|
|
)
|
|
.all() as { sql: string }[];
|
|
const sequence = handle
|
|
.prepare("SELECT seq FROM sqlite_sequence WHERE name='script_versions'")
|
|
.get() as { seq: number } | undefined;
|
|
handle.pragma('foreign_keys = OFF');
|
|
try {
|
|
handle.transaction(() => {
|
|
handle.exec(replacement);
|
|
const names = columns.map((column) => `"${column.name}"`).join(',');
|
|
handle.exec(`INSERT INTO script_versions_metadata (${names}) SELECT ${names} FROM script_versions;
|
|
DROP TABLE script_versions; ALTER TABLE script_versions_metadata RENAME TO script_versions;`);
|
|
if (sequence)
|
|
handle
|
|
.prepare(
|
|
"UPDATE sqlite_sequence SET seq=MAX(seq,?) WHERE name='script_versions'"
|
|
)
|
|
.run(sequence.seq);
|
|
for (const dependent of dependents) handle.exec(dependent.sql);
|
|
if ((handle.pragma('foreign_key_check') as unknown[]).length)
|
|
throw new Error('Version layout migration found broken references');
|
|
})();
|
|
} finally {
|
|
handle.pragma('foreign_keys = ON');
|
|
}
|
|
}
|