mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
0440 adds its columns with ADD COLUMN IF NOT EXISTS like 0424 and 0432; a structural test holds every migration from 0422 on to that form. 0430 clears insights_cached_at where no sealed payload is left, so the nightly pregenerate refills an account whose only copy was the readable column instead of keeping an empty card fresh. The deploy runbook notes that 0430 drops a users column: an old process fails on its next full user read, so stop before starting rather than running old and new side by side.
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
/**
|
|
* Structural guard: a column a migration adds is added idempotently.
|
|
*
|
|
* Parallel release branches each add columns to `users`, and a host that ran
|
|
* a beta image already holds the columns a later rebuilt migration adds again.
|
|
* A bare `ADD COLUMN` then fails the boot with "column already exists". Every
|
|
* migration from `0422` on (the first one after the last release that shipped
|
|
* a bare form) writes `ADD COLUMN IF NOT EXISTS`, as `0424` and `0432` did from
|
|
* the start.
|
|
*/
|
|
import { readdirSync, readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
const MIGRATIONS_DIR = resolve(
|
|
dirname(fileURLToPath(import.meta.url)),
|
|
"../../prisma/migrations",
|
|
);
|
|
|
|
const FIRST_GUARDED = 422;
|
|
|
|
/** Lines that add a column without `IF NOT EXISTS`, comments stripped. */
|
|
function bareAddColumns(sql: string): string[] {
|
|
return sql
|
|
.split("\n")
|
|
.map((line) => line.replace(/--.*$/, ""))
|
|
.filter((line) => /\bADD\s+COLUMN\b/i.test(line))
|
|
.filter((line) => !/\bADD\s+COLUMN\s+IF\s+NOT\s+EXISTS\b/i.test(line))
|
|
.map((line) => line.trim());
|
|
}
|
|
|
|
describe("migrations add columns idempotently", () => {
|
|
it("recognises the bare form and accepts the guarded one", () => {
|
|
expect(
|
|
bareAddColumns('ALTER TABLE "u" ADD COLUMN "a" JSONB;'),
|
|
).toHaveLength(1);
|
|
expect(
|
|
bareAddColumns('ALTER TABLE "u" ADD COLUMN IF NOT EXISTS "a" JSONB;'),
|
|
).toEqual([]);
|
|
expect(bareAddColumns("-- ADD COLUMN in a comment")).toEqual([]);
|
|
});
|
|
|
|
it(`uses ADD COLUMN IF NOT EXISTS from ${FIRST_GUARDED} on`, () => {
|
|
const offenders: string[] = [];
|
|
for (const entry of readdirSync(MIGRATIONS_DIR, { withFileTypes: true })) {
|
|
if (!entry.isDirectory()) continue;
|
|
const number = Number.parseInt(entry.name.slice(0, 4), 10);
|
|
if (!Number.isFinite(number) || number < FIRST_GUARDED) continue;
|
|
const sql = readFileSync(
|
|
resolve(MIGRATIONS_DIR, entry.name, "migration.sql"),
|
|
"utf8",
|
|
);
|
|
for (const line of bareAddColumns(sql)) {
|
|
offenders.push(`${entry.name}: ${line}`);
|
|
}
|
|
}
|
|
expect(offenders).toEqual([]);
|
|
});
|
|
});
|