Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Chris Parsons <chrisparsons1127@gmail.com> Reviewed-on: #98
78 lines
2.5 KiB
JavaScript
78 lines
2.5 KiB
JavaScript
/**
|
|
* One-off data migration: fix group-stage match times stored as local-wall-time-as-UTC.
|
|
*
|
|
* Before the schedule-form fix, the admin's local wall-clock time (PDT, UTC-7) was
|
|
* stored as if it were UTC, so every `group_stage_matches.scheduled_at` is 7 hours
|
|
* behind the true UTC instant. This shifts them +7 hours.
|
|
*
|
|
* Scope: ONLY `group_stage_matches.scheduled_at` (where not null). Playoff games
|
|
* (`playoff_match_games.scheduled_at`) were saved correctly and are left untouched.
|
|
*
|
|
* NOT idempotent — running with --apply twice double-shifts. Defaults to a dry-run;
|
|
* pass --apply to write.
|
|
*
|
|
* Usage (loads .env via dotenv-cli):
|
|
* npx dotenv -- node scripts/fix-group-match-times-utc.mjs # preview
|
|
* npx dotenv -- node scripts/fix-group-match-times-utc.mjs --apply # apply
|
|
*/
|
|
|
|
import postgres from "postgres";
|
|
|
|
const SHIFT = "7 hours"; // PDT (UTC-7) wall-clock stored as UTC -> true UTC
|
|
const apply = process.argv.includes("--apply");
|
|
|
|
const DATABASE_URL = process.env.DATABASE_DIRECT_URL || process.env.DATABASE_URL;
|
|
if (!DATABASE_URL) {
|
|
console.error("ERROR: DATABASE_DIRECT_URL (or DATABASE_URL) is required");
|
|
process.exit(1);
|
|
}
|
|
|
|
const sql = postgres(DATABASE_URL, { max: 1, onnotice: () => {} });
|
|
|
|
try {
|
|
const [{ count }] = await sql`
|
|
SELECT COUNT(*)::int AS count
|
|
FROM group_stage_matches
|
|
WHERE scheduled_at IS NOT NULL
|
|
`;
|
|
console.log(`Group-stage matches with a scheduled time: ${count}`);
|
|
|
|
if (count === 0) {
|
|
console.log("Nothing to do.");
|
|
await sql.end();
|
|
process.exit(0);
|
|
}
|
|
|
|
const samples = await sql`
|
|
SELECT id,
|
|
scheduled_at AS before,
|
|
scheduled_at + ${sql.unsafe(`interval '${SHIFT}'`)} AS after
|
|
FROM group_stage_matches
|
|
WHERE scheduled_at IS NOT NULL
|
|
ORDER BY scheduled_at
|
|
LIMIT 10
|
|
`;
|
|
console.log(`\nSample before -> after (+${SHIFT}):`);
|
|
for (const r of samples) {
|
|
console.log(` ${r.id}: ${r.before.toISOString()} -> ${r.after.toISOString()}`);
|
|
}
|
|
|
|
if (!apply) {
|
|
console.log(`\nDRY RUN — no changes written. Re-run with --apply to shift ${count} row(s) +${SHIFT}.`);
|
|
await sql.end();
|
|
process.exit(0);
|
|
}
|
|
|
|
const result = await sql`
|
|
UPDATE group_stage_matches
|
|
SET scheduled_at = scheduled_at + ${sql.unsafe(`interval '${SHIFT}'`)}
|
|
WHERE scheduled_at IS NOT NULL
|
|
`;
|
|
console.log(`\nApplied: shifted ${result.count} row(s) +${SHIFT}.`);
|
|
await sql.end();
|
|
process.exit(0);
|
|
} catch (err) {
|
|
console.error("Migration failed:", err);
|
|
await sql.end().catch(() => {});
|
|
process.exit(1);
|
|
}
|