SPB Git

Repository Public MIT

migrate.ts 1.4 KB 30 lines typescript

1import { createHash } from "node:crypto";2import { readdirSync, readFileSync } from "node:fs";3import { dirname, join } from "node:path";4import { fileURLToPath } from "node:url";5import type { Sql } from "./index";67export const MIGRATIONS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "migrations");89/** Forward-only, checksummed SQL migrations. A changed, already-applied file aborts the run. */10export async function migrate(sql: Sql, dir: string = MIGRATIONS_DIR): Promise<string[]> {11  await sql`CREATE TABLE IF NOT EXISTS schema_migrations (name text PRIMARY KEY, checksum text NOT NULL, applied_at timestamptz NOT NULL DEFAULT now())`;12  const applied = new Map((await sql<{ name: string; checksum: string }[]>`SELECT name, checksum FROM schema_migrations`).map((r) => [r.name, r.checksum]));13  const done: string[] = [];14  for (const name of readdirSync(dir).filter((f) => /^\d{4}_.+\.sql$/.test(f)).sort()) {15    const body = readFileSync(join(dir, name), "utf8");16    const checksum = createHash("sha256").update(body).digest("hex");17    const prev = applied.get(name);18    if (prev) {19      if (prev !== checksum) throw new Error(`migration ${name} was modified after being applied; write a new migration instead`);20      continue;21    }22    await sql.begin(async (tx) => {23      await tx.unsafe(body);24      await tx`INSERT INTO schema_migrations (name, checksum) VALUES (${name}, ${checksum})`;25    });26    done.push(name);27  }28  return done;29}30
Files main
Menu

Theme