feat(learner): package scaffold, auth tables migration, migrations runner
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0b117159cd
commit
5a215744e5
@@ -0,0 +1,33 @@
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import type { Db } from "@stc/db";
|
||||
|
||||
/** Folders holding this package's migrations; Phase 2 wires these into `migrate()`. */
|
||||
export const migrationsDirs: string[] = [join(import.meta.dir, "..", "..", "migrations")];
|
||||
|
||||
function statements(text: string): string[] {
|
||||
const noComments = text.split("\n").filter((l) => !l.trim().startsWith("--")).join("\n");
|
||||
return noComments.split(";").map((s) => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the learner migrations with the same bookkeeping as `@stc/db`'s `migrate()`
|
||||
* (table `schema_migrations`, keyed by file name). Safe to call repeatedly.
|
||||
*/
|
||||
export async function runMigrations(db: Db, dirs: string[] = migrationsDirs): Promise<string[]> {
|
||||
await db.sql.unsafe("CREATE TABLE IF NOT EXISTS schema_migrations (name TEXT PRIMARY KEY, applied_at TEXT NOT NULL)");
|
||||
const done = new Set((await db.sql`SELECT name FROM schema_migrations`).map((r: { name: string }) => r.name));
|
||||
const applied: string[] = [];
|
||||
for (const dir of dirs) {
|
||||
for (const name of readdirSync(dir).filter((f) => f.endsWith(".sql")).sort()) {
|
||||
if (done.has(name)) continue;
|
||||
const stmts = statements(readFileSync(join(dir, name), "utf8"));
|
||||
await db.sql.begin(async (tx) => {
|
||||
for (const s of stmts) await tx.unsafe(s);
|
||||
await tx`INSERT INTO schema_migrations (name, applied_at) VALUES (${name}, ${new Date().toISOString()})`;
|
||||
});
|
||||
applied.push(name);
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
}
|
||||
Reference in New Issue
Block a user