sendou.ink/scripts/backfill-tournament-result-divisions.ts
Kalle 9fc30a7624
Some checks are pending
E2E Tests / e2e (push) Waiting to run
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
Many starting brackets standings (#2611)
2025-11-03 21:30:22 +02:00

136 lines
4.1 KiB
TypeScript

import "dotenv/config";
import { db } from "../app/db/sql";
import * as Seasons from "../app/features/mmr/core/Seasons";
import {
queryCurrentTeamRating,
queryCurrentUserRating,
queryCurrentUserSeedingRating,
queryTeamPlayerRatingAverage,
} from "../app/features/mmr/mmr-utils.server";
import * as Standings from "../app/features/tournament/core/Standings";
import { tournamentSummary } from "../app/features/tournament-bracket/core/summarizer.server";
import { tournamentFromDB } from "../app/features/tournament-bracket/core/Tournament.server";
import { allMatchResultsByTournamentId } from "../app/features/tournament-bracket/queries/allMatchResultsByTournamentId.server";
import invariant from "../app/utils/invariant";
import { logger } from "../app/utils/logger";
async function main() {
logger.info("Starting to backfill tournament result divisions");
const tournaments = await db
.selectFrom("Tournament")
.select("id")
.where("isFinalized", "=", 1)
.execute();
let recalculatedCount = 0;
let skippedCount = 0;
for (const { id: tournamentId } of tournaments) {
try {
const tournament = await tournamentFromDB({
tournamentId,
user: undefined,
});
const uniqueStartingBracketIndexes = new Set(
tournament.ctx.teams
.map((team) => team.startingBracketIdx)
.filter((idx) => idx !== null && idx !== undefined),
);
if (uniqueStartingBracketIndexes.size <= 1) {
skippedCount++;
continue;
}
recalculatedCount++;
await db
.deleteFrom("TournamentResult")
.where("tournamentId", "=", tournamentId)
.execute();
const results = allMatchResultsByTournamentId(tournamentId);
invariant(results.length > 0, "No results found");
const season = Seasons.current(tournament.ctx.startTime)?.nth;
const seedingSkillCountsFor = tournament.skillCountsFor;
const standingsResult = Standings.tournamentStandings(tournament);
if (standingsResult.type === "single") {
throw new Error(
`Expected multiple starting brackets for tournament ${tournamentId}`,
);
}
const finalStandings = Standings.flattenStandings(standingsResult);
const summary = tournamentSummary({
teams: tournament.ctx.teams,
finalStandings,
results,
calculateSeasonalStats: false,
queryCurrentTeamRating: (identifier) =>
queryCurrentTeamRating({ identifier, season: season! }).rating,
queryCurrentUserRating: (userId) =>
queryCurrentUserRating({ userId, season: season! }),
queryTeamPlayerRatingAverage: (identifier) =>
queryTeamPlayerRatingAverage({
identifier,
season: season!,
}),
queryCurrentSeedingRating: (userId) =>
queryCurrentUserSeedingRating({
userId,
type: seedingSkillCountsFor!,
}),
seedingSkillCountsFor,
progression: tournament.ctx.settings.bracketProgression,
});
logger.info(
`Inserting ${summary.tournamentResults.length} results for tournament ${tournamentId}`,
);
for (const tournamentResult of summary.tournamentResults) {
const setResults = summary.setResults.get(tournamentResult.userId);
if (setResults?.every((result) => !result)) {
continue;
}
await db
.insertInto("TournamentResult")
.values({
tournamentId,
userId: tournamentResult.userId,
placement: tournamentResult.placement,
participantCount: tournamentResult.participantCount,
tournamentTeamId: tournamentResult.tournamentTeamId,
setResults: setResults ? JSON.stringify(setResults) : "[]",
spDiff: null,
div: tournamentResult.div,
})
.execute();
}
if (recalculatedCount % 10 === 0) {
logger.info(
`Processed ${recalculatedCount} tournaments with multiple starting brackets (skipped ${skippedCount})`,
);
}
} catch (thrown) {
if (thrown instanceof Response) continue;
logger.error(`Error processing tournament ${tournamentId}`, thrown);
}
}
logger.info(
`Done. Recalculated ${recalculatedCount} tournaments with multiple starting brackets. Skipped ${skippedCount} tournaments.`,
);
}
main().catch((err) => {
logger.error("Error in backfill-tournament-result-divisions.ts", err);
process.exit(1);
});