test(migrations): cover initial schema, idempotency, and legacy upgrade
Some checks failed
CI / check (push) Failing after 17s
Some checks failed
CI / check (push) Failing after 17s
This commit is contained in:
115
tests/migrations_test.ts
Normal file
115
tests/migrations_test.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import { assertEquals } from "@std/assert";
|
||||||
|
import { Database } from "@db/sqlite";
|
||||||
|
import { applyMigrations } from "../src/migrations/apply.ts";
|
||||||
|
|
||||||
|
type TableInfoRow = { name: string };
|
||||||
|
type ColumnInfoRow = { name: string };
|
||||||
|
|
||||||
|
const tableNames = (db: Database): string[] =>
|
||||||
|
db.prepare(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name",
|
||||||
|
).all<TableInfoRow>().map((r) => r.name);
|
||||||
|
|
||||||
|
const columnNames = (db: Database, table: string): string[] =>
|
||||||
|
db.prepare(`PRAGMA table_info(${table})`)
|
||||||
|
.all<ColumnInfoRow>()
|
||||||
|
.map((r) => r.name)
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
const indexNames = (db: Database): string[] =>
|
||||||
|
db.prepare(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_%' ORDER BY name",
|
||||||
|
).all<TableInfoRow>().map((r) => r.name);
|
||||||
|
|
||||||
|
Deno.test("applyMigrations creates expected tables, columns, and indices", () => {
|
||||||
|
const db = new Database(":memory:");
|
||||||
|
try {
|
||||||
|
applyMigrations(db);
|
||||||
|
|
||||||
|
const tables = tableNames(db);
|
||||||
|
assertEquals(
|
||||||
|
tables.includes("note") &&
|
||||||
|
tables.includes("state") &&
|
||||||
|
tables.includes("webhook_subscription"),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
const noteCols = columnNames(db, "note");
|
||||||
|
for (
|
||||||
|
const col of [
|
||||||
|
"title",
|
||||||
|
"publishedAt",
|
||||||
|
"createdAt",
|
||||||
|
"did",
|
||||||
|
"rkey",
|
||||||
|
"discoverable",
|
||||||
|
"language",
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
assertEquals(noteCols.includes(col), true, `note.${col} missing`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const webhookCols = columnNames(db, "webhook_subscription");
|
||||||
|
for (const col of ["id", "did", "method", "url", "token", "verb"]) {
|
||||||
|
assertEquals(
|
||||||
|
webhookCols.includes(col),
|
||||||
|
true,
|
||||||
|
`webhook_subscription.${col} missing`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const indices = indexNames(db);
|
||||||
|
assertEquals(indices.includes("idx_webhook_subscription_did"), true);
|
||||||
|
assertEquals(indices.includes("idx_webhook_subscription_did_verb"), true);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("applyMigrations is idempotent", () => {
|
||||||
|
const db = new Database(":memory:");
|
||||||
|
try {
|
||||||
|
applyMigrations(db);
|
||||||
|
db.exec(
|
||||||
|
"INSERT INTO webhook_subscription (did, method, url, verb) VALUES ('did:plc:x', 'POST', 'https://e.com', 'create')",
|
||||||
|
);
|
||||||
|
applyMigrations(db);
|
||||||
|
applyMigrations(db);
|
||||||
|
|
||||||
|
const [{ count }] = db.prepare(
|
||||||
|
"SELECT COUNT(*) AS count FROM webhook_subscription WHERE did = 'did:plc:x' AND verb = 'create'",
|
||||||
|
).all<{ count: number }>();
|
||||||
|
assertEquals(count, 1);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
"applyMigrations upgrades a legacy schema missing language and discoverable",
|
||||||
|
() => {
|
||||||
|
const db = new Database(":memory:");
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE note (
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
publishedAt DATETIME,
|
||||||
|
createdAt DATETIME NOT NULL,
|
||||||
|
did TEXT NOT NULL,
|
||||||
|
rkey TEXT NOT NULL,
|
||||||
|
listed INTEGER NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (did, rkey)
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
|
||||||
|
applyMigrations(db);
|
||||||
|
|
||||||
|
const cols = columnNames(db, "note");
|
||||||
|
assertEquals(cols.includes("discoverable"), true);
|
||||||
|
assertEquals(cols.includes("language"), true);
|
||||||
|
assertEquals(cols.includes("listed"), false);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user