28 lines
1.2 KiB
TypeScript
28 lines
1.2 KiB
TypeScript
import { readdirSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import type { Db } from "./connect";
|
|
|
|
const MIGRATIONS_DIR = join(import.meta.dir, "..", "migrations");
|
|
|
|
function statements(text: string): string[] {
|
|
const noComments = text.split("\n").filter((l) => !l.trim().startsWith("--")).join("\n");
|
|
return noComments.split(";").map((s) => s.trim()).filter(Boolean);
|
|
}
|
|
|
|
export async function migrate(db: Db): Promise<string[]> {
|
|
await db.sql.unsafe("CREATE TABLE IF NOT EXISTS schema_migrations (name TEXT PRIMARY KEY, applied_at TEXT NOT NULL)");
|
|
const done = new Set((await db.sql`SELECT name FROM schema_migrations`).map((r: { name: string }) => r.name));
|
|
const files = readdirSync(MIGRATIONS_DIR).filter((f) => f.endsWith(".sql")).sort();
|
|
const applied: string[] = [];
|
|
for (const name of files) {
|
|
if (done.has(name)) continue;
|
|
const stmts = statements(readFileSync(join(MIGRATIONS_DIR, name), "utf8"));
|
|
await db.sql.begin(async (tx) => {
|
|
for (const s of stmts) await tx.unsafe(s);
|
|
await tx`INSERT INTO schema_migrations (name, applied_at) VALUES (${name}, ${new Date().toISOString()})`;
|
|
});
|
|
applied.push(name);
|
|
}
|
|
return applied;
|
|
}
|