116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
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();
|
|
}
|
|
},
|
|
);
|