scripts: add backfill CLI with dry-run default
Wires backfill-canonical-layer.ts to a CLI entry point exposed as `npm run backfill:canonical`. Defaults to --dry-run; requires --apply to actually write. Supports --sport=<uuid> to limit to a single sport. Exits 2 if the backfill reports errors (e.g., surface-Elo conflicts).
This commit is contained in:
parent
8186dbb525
commit
6f3438b5d2
2 changed files with 79 additions and 0 deletions
|
|
@ -9,6 +9,7 @@
|
|||
"db:generate": "dotenv -- drizzle-kit generate",
|
||||
"db:migrate": "dotenv -- drizzle-kit migrate",
|
||||
"db:sync-prod": "bash scripts/sync-prod-db.sh",
|
||||
"backfill:canonical": "dotenv -- tsx scripts/backfill-cli.ts",
|
||||
"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' dotenv -- tsx watch server.ts",
|
||||
"start": "NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' node dist/server.js",
|
||||
"start:production": "NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' node dist/server.js",
|
||||
|
|
|
|||
78
scripts/backfill-cli.ts
Normal file
78
scripts/backfill-cli.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* CLI entry point for the Phase 2 canonical backfill.
|
||||
*
|
||||
* Usage:
|
||||
* npm run backfill:canonical -- [--dry-run | --apply] [--sport=<uuid>]
|
||||
*
|
||||
* Defaults to --dry-run for safety. No writes will be issued unless
|
||||
* --apply is passed explicitly.
|
||||
*/
|
||||
|
||||
import { runBackfill } from "./backfill-canonical-layer";
|
||||
import type { BackfillOptions } from "./backfill-canonical-layer";
|
||||
|
||||
function printHelp(): void {
|
||||
console.log(
|
||||
[
|
||||
"Usage: backfill-cli [options]",
|
||||
"",
|
||||
"Options:",
|
||||
" --dry-run Run without writing (default).",
|
||||
" --apply Actually write to the database.",
|
||||
" --sport=<uuid> Only backfill for the given sport id.",
|
||||
" --help Show this message.",
|
||||
].join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
function parseArgs(): BackfillOptions {
|
||||
const args = process.argv.slice(2);
|
||||
const opts: BackfillOptions = { dryRun: true }; // dry-run by default for safety
|
||||
for (const a of args) {
|
||||
if (a === "--apply") {
|
||||
opts.dryRun = false;
|
||||
} else if (a === "--dry-run") {
|
||||
opts.dryRun = true;
|
||||
} else if (a.startsWith("--sport=")) {
|
||||
opts.sportId = a.slice("--sport=".length);
|
||||
} else if (a === "--help" || a === "-h") {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.error(`unknown arg: ${a}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const opts = parseArgs();
|
||||
console.log(
|
||||
`Running backfill (dryRun=${opts.dryRun}, sportId=${opts.sportId ?? "all"})`,
|
||||
);
|
||||
const report = await runBackfill(opts);
|
||||
|
||||
console.log("---");
|
||||
console.log(`tournamentsCreated: ${report.tournamentsCreated}`);
|
||||
console.log(`tournamentsLinked: ${report.tournamentsLinked}`);
|
||||
console.log(`participantsCreated: ${report.participantsCreated}`);
|
||||
console.log(`participantsLinked: ${report.participantsLinked}`);
|
||||
console.log(`tournamentResultsCreated: ${report.tournamentResultsCreated}`);
|
||||
console.log(`surfaceElosCreated: ${report.surfaceElosCreated}`);
|
||||
|
||||
if (report.warnings.length) {
|
||||
console.log("\nWARNINGS:");
|
||||
for (const w of report.warnings) console.log(` ${w}`);
|
||||
}
|
||||
if (report.errors.length) {
|
||||
console.log("\nERRORS:");
|
||||
for (const e of report.errors) console.log(` ${e}`);
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue