import type { DatabaseSync } from "node:sqlite"; import { up as up0001CommentLikes } from "./migrations/0001_comment_likes.ts"; import { up as up0002DumpThumbnail } from "./migrations/0002_dump_thumbnail.ts"; import { up as up0003DumpBacklinks } from "./migrations/0003_dump_backlinks.ts"; import { up as up0004UserRoles } from "./migrations/0004_user_roles.ts"; import { up as up0005DropIsAdmin } from "./migrations/0005_drop_is_admin.ts"; import { up as up0006Categories } from "./migrations/0006_categories.ts"; import { up as up0007PasswordResetTokens } from "./migrations/0007_password_reset_tokens.ts"; import { up as up0008ChatMessages } from "./migrations/0008_chat_messages.ts"; interface Migration { name: string; up: (db: DatabaseSync) => void; } // Append-only — never edit or reorder a migration once it has shipped. // Each `up` must be idempotent: it also runs against fresh databases created // straight from schema.sql, where the change it makes already exists. const MIGRATIONS: Migration[] = [ { name: "0001_comment_likes", up: up0001CommentLikes }, { name: "0002_dump_thumbnail", up: up0002DumpThumbnail }, { name: "0003_dump_backlinks", up: up0003DumpBacklinks }, { name: "0004_user_roles", up: up0004UserRoles }, { name: "0005_drop_is_admin", up: up0005DropIsAdmin }, { name: "0006_categories", up: up0006Categories }, { name: "0007_password_reset_tokens", up: up0007PasswordResetTokens }, { name: "0008_chat_messages", up: up0008ChatMessages }, ]; export function runMigrations(db: DatabaseSync): void { db.exec(`CREATE TABLE IF NOT EXISTS schema_migrations ( name TEXT PRIMARY KEY, applied_at TEXT NOT NULL );`); const applied = new Set( (db.prepare(`SELECT name FROM schema_migrations;`).all() as { name: string; }[]).map((r) => r.name), ); for (const { name, up } of MIGRATIONS) { if (applied.has(name)) continue; db.exec("BEGIN;"); try { up(db); db.prepare( `INSERT INTO schema_migrations (name, applied_at) VALUES (?, ?);`, ).run(name, new Date().toISOString()); db.exec("COMMIT;"); console.log(`[migrate] applied ${name}`); } catch (err) { db.exec("ROLLBACK;"); throw err; } } }