113 lines
3.8 KiB
TypeScript
113 lines
3.8 KiB
TypeScript
/**
|
|
* One-time migration: MariaDB → PostgreSQL
|
|
*
|
|
* Reads all data from the existing MariaDB database and inserts into PostgreSQL.
|
|
* Requires both DATABASE_URL (postgres) and MARIA_* env vars.
|
|
*
|
|
* Usage: node --env-file=.env scripts/migrate-data.ts
|
|
*/
|
|
import mysql from "mysql2/promise";
|
|
import postgres from "postgres";
|
|
|
|
const MARIA_HOST = process.env.MARIA_HOST ?? "127.0.0.1";
|
|
const MARIA_PORT = Number(process.env.MARIA_PORT ?? 3306);
|
|
const MARIA_USER = process.env.MARIA_USER ?? "serve";
|
|
const MARIA_PASS = process.env.MARIA_PASS ?? "";
|
|
const MARIA_DB = process.env.MARIA_DB ?? "serve";
|
|
const PG_URL = process.env.DATABASE_URL;
|
|
|
|
if (!PG_URL) {
|
|
console.error("DATABASE_URL is required");
|
|
process.exit(1);
|
|
}
|
|
|
|
const maria = await mysql.createConnection({
|
|
host: MARIA_HOST,
|
|
port: MARIA_PORT,
|
|
user: MARIA_USER,
|
|
password: MARIA_PASS,
|
|
database: MARIA_DB,
|
|
timezone: "+00:00",
|
|
});
|
|
|
|
const pgUrl = new URL(PG_URL);
|
|
const socketHost = pgUrl.searchParams.get("host");
|
|
const pg = postgres({
|
|
host: socketHost ?? pgUrl.hostname,
|
|
port: Number(pgUrl.port) || 5432,
|
|
database: pgUrl.pathname.slice(1),
|
|
username: pgUrl.username,
|
|
password: pgUrl.password,
|
|
});
|
|
|
|
// Order: rounds → round_users → movies → votes → round_history (FK constraint order)
|
|
|
|
console.log("Migrating rounds...");
|
|
const [roundRows] = await maria.execute("SELECT * FROM rounds");
|
|
for (const r of roundRows as mysql.RowDataPacket[]) {
|
|
await pg`
|
|
INSERT INTO rounds (uuid, phase, setup_done, created_at, updated_at)
|
|
VALUES (${r.uuid}, ${r.phase}, ${Boolean(r.setup_done)}, ${r.created_at}, ${r.updated_at})
|
|
ON CONFLICT (uuid) DO NOTHING
|
|
`;
|
|
}
|
|
console.log(` ${(roundRows as mysql.RowDataPacket[]).length} rounds`);
|
|
|
|
console.log("Migrating round_users...");
|
|
const [userRows] = await maria.execute("SELECT * FROM round_users");
|
|
for (const u of userRows as mysql.RowDataPacket[]) {
|
|
await pg`
|
|
INSERT INTO round_users (round_uuid, name, done_phase1, done_phase2, sort_order)
|
|
VALUES (${u.round_uuid}, ${u.name}, ${Boolean(u.done_phase1)}, ${Boolean(u.done_phase2)}, ${u.sort_order})
|
|
ON CONFLICT (round_uuid, name) DO NOTHING
|
|
`;
|
|
}
|
|
console.log(` ${(userRows as mysql.RowDataPacket[]).length} users`);
|
|
|
|
console.log("Migrating movies...");
|
|
const [movieRows] = await maria.execute("SELECT * FROM movies ORDER BY id");
|
|
for (const m of movieRows as mysql.RowDataPacket[]) {
|
|
await pg`
|
|
INSERT INTO movies (id, round_uuid, title, added_by, added_at)
|
|
VALUES (${m.id}, ${m.round_uuid}, ${m.title}, ${m.added_by}, ${m.added_at})
|
|
ON CONFLICT DO NOTHING
|
|
`;
|
|
}
|
|
console.log(` ${(movieRows as mysql.RowDataPacket[]).length} movies`);
|
|
|
|
// Reset the serial sequence for movies.id
|
|
await pg`SELECT setval('movies_id_seq', COALESCE((SELECT MAX(id) FROM movies), 0) + 1)`;
|
|
|
|
console.log("Migrating votes...");
|
|
const [voteRows] = await maria.execute("SELECT * FROM votes");
|
|
for (const v of voteRows as mysql.RowDataPacket[]) {
|
|
await pg`
|
|
INSERT INTO votes (round_uuid, user_name, movie_title, rating)
|
|
VALUES (${v.round_uuid}, ${v.user_name}, ${v.movie_title}, ${v.rating})
|
|
ON CONFLICT (round_uuid, user_name, movie_title) DO NOTHING
|
|
`;
|
|
}
|
|
console.log(` ${(voteRows as mysql.RowDataPacket[]).length} votes`);
|
|
|
|
console.log("Migrating round_history...");
|
|
const [historyRows] = await maria.execute(
|
|
"SELECT * FROM round_history ORDER BY id",
|
|
);
|
|
for (const h of historyRows as mysql.RowDataPacket[]) {
|
|
await pg`
|
|
INSERT INTO round_history (id, round_uuid, winner, movies_json, created_at)
|
|
VALUES (${h.id}, ${h.round_uuid}, ${h.winner}, ${h.movies_json}, ${h.created_at})
|
|
ON CONFLICT DO NOTHING
|
|
`;
|
|
}
|
|
console.log(
|
|
` ${(historyRows as mysql.RowDataPacket[]).length} history entries`,
|
|
);
|
|
|
|
// Reset the serial sequence for round_history.id
|
|
await pg`SELECT setval('round_history_id_seq', COALESCE((SELECT MAX(id) FROM round_history), 0) + 1)`;
|
|
|
|
console.log("Migration complete!");
|
|
await maria.end();
|
|
await pg.end();
|