44 lines
2.0 KiB
TypeScript
44 lines
2.0 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { openDatabase, migrate } from "../src/database.js";
|
|
|
|
const steps = [{ version: 1, name: "projects", sql: "CREATE TABLE projects (id INTEGER PRIMARY KEY, name TEXT NOT NULL) STRICT;" }];
|
|
|
|
test("migrations persist, reopen idempotently, and allow unrelated tables", () => {
|
|
const directory = mkdtempSync(join(tmpdir(), "token-db-"));
|
|
try {
|
|
const path = join(directory, "nested/state.sqlite");
|
|
const first = openDatabase(path, steps);
|
|
first.prepare("INSERT INTO projects (name) VALUES (?)").run("garden");
|
|
first.close();
|
|
const second = openDatabase(path, steps);
|
|
try {
|
|
assert.equal(second.prepare("SELECT name FROM projects").get()?.name, "garden");
|
|
assert.equal(second.prepare("PRAGMA foreign_keys").get()?.foreign_keys, 1);
|
|
assert.equal(second.prepare("PRAGMA journal_mode").get()?.journal_mode, "wal");
|
|
assert.throws(() => migrate(second, []), /history differs/);
|
|
assert.throws(() => migrate(second, [{ version: 1, name: "projects", sql: "SELECT 1" }]), /history differs/);
|
|
} finally {
|
|
second.close();
|
|
}
|
|
} finally {
|
|
rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("failed migrations roll back schema changes and history", () => {
|
|
const database = openDatabase(":memory:", steps);
|
|
try {
|
|
assert.throws(() => migrate(database, [...steps, {
|
|
version: 2, name: "broken", sql: "CREATE TABLE temporary_table (id INTEGER); INVALID SQL;",
|
|
}]));
|
|
assert.equal(database.prepare("SELECT count(*) AS count FROM schema_migrations").get()?.count, 1);
|
|
assert.equal(database.prepare("SELECT name FROM sqlite_master WHERE name = 'temporary_table'").get(), undefined);
|
|
} finally {
|
|
database.close();
|
|
}
|
|
});
|