feat: redesign match play and add broadcast tooling
This commit is contained in:
51
scripts/migrate.ts
Normal file
51
scripts/migrate.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Applies scripts/migrations/*.sql in name order, once each, inside one
|
||||
* transaction. Applied names are recorded in schema_migration.
|
||||
*
|
||||
* bun scripts/migrate.ts apply pending migrations
|
||||
* bun scripts/migrate.ts --status list applied and pending migrations
|
||||
*
|
||||
* Every migration is additive and idempotent, so a database that was set up
|
||||
* with drizzle-kit push or the old migrate-platform script is safe to run.
|
||||
*/
|
||||
import { SQL } from 'bun';
|
||||
import { readdir, readFile } from 'node:fs/promises';
|
||||
|
||||
const databaseUrl = process.env.DB_URL || process.env.DATABASE_URL;
|
||||
if (!databaseUrl) throw new Error('DB_URL or DATABASE_URL is required');
|
||||
|
||||
const directory = new URL('./migrations/', import.meta.url);
|
||||
const files = (await readdir(directory)).filter((name) => name.endsWith('.sql')).sort();
|
||||
const sql = new SQL(databaseUrl, { max: 1 });
|
||||
|
||||
try {
|
||||
await sql`CREATE TABLE IF NOT EXISTS schema_migration (name text PRIMARY KEY, applied_at timestamptz NOT NULL DEFAULT now())`;
|
||||
const applied = new Set(
|
||||
((await sql`SELECT name FROM schema_migration`) as { name: string }[]).map((row) => row.name)
|
||||
);
|
||||
const pending = files.filter((name) => !applied.has(name));
|
||||
|
||||
if (process.argv.includes('--status')) {
|
||||
for (const name of files) console.log(`${applied.has(name) ? 'applied' : 'pending'} ${name}`);
|
||||
} else if (pending.length === 0) {
|
||||
console.log('Database is up to date');
|
||||
} else {
|
||||
await sql.begin(async (tx) => {
|
||||
for (const name of pending) {
|
||||
await tx.unsafe(await readFile(new URL(name, directory), 'utf8'));
|
||||
await tx`INSERT INTO schema_migration (name) VALUES (${name})`;
|
||||
console.log(`applied ${name}`);
|
||||
}
|
||||
// The root administrator is configured per environment, never guessed.
|
||||
const rootId = process.env.ROOT_ADMIN_USER_ID;
|
||||
const legacyRoot = process.env.ROOT_ADMIN_EMAIL;
|
||||
if (rootId)
|
||||
await tx`UPDATE "user" SET root_admin = true, role = 'admin' WHERE id = ${rootId}`;
|
||||
else if (legacyRoot)
|
||||
await tx`UPDATE "user" SET root_admin = true, role = 'admin' WHERE lower(email) = ${legacyRoot.toLowerCase()}`;
|
||||
});
|
||||
console.log(`${pending.length} migration(s) applied atomically`);
|
||||
}
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
Reference in New Issue
Block a user