feat: per-window batch-add-results routes through canonical when linked
If the scoring_event has a tournament_id, translate season_participant ids to canonical participant ids, upsert tournament_results, and fan out via syncTournamentResults. Team sports (no tournament link) keep the legacy direct-write path. Phase 3 Task 8 of canonical tournament layer migration. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
3a4fe41eb5
commit
3e81dfe8da
1 changed files with 42 additions and 0 deletions
|
|
@ -27,6 +27,8 @@ import { getQPStandings, getQPConfig } from "~/models/qualifying-points";
|
|||
import { database } from "~/database/context";
|
||||
import * as schema from "~/database/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { upsertTournamentResult } from "~/models/tournament-result";
|
||||
import { syncTournamentResults } from "~/services/sync-tournament-results";
|
||||
|
||||
export async function loader({ params }: Route.LoaderArgs) {
|
||||
const sportsSeason = await findSportsSeasonById(params.id);
|
||||
|
|
@ -372,6 +374,46 @@ export async function action({ request, params }: Route.ActionArgs) {
|
|||
}
|
||||
|
||||
try {
|
||||
// If this scoring event is linked to a canonical tournament, write
|
||||
// results to the canonical layer and fan out via syncTournamentResults.
|
||||
// This keeps sibling windows (if any) in sync automatically.
|
||||
const scoringEvent = await database().query.scoringEvents.findFirst({
|
||||
where: eq(schema.scoringEvents.id, params.eventId),
|
||||
});
|
||||
if (!scoringEvent) {
|
||||
return { error: "Scoring event not found" };
|
||||
}
|
||||
|
||||
if (scoringEvent.tournamentId) {
|
||||
// Canonical path: translate season_participant.id → canonical participant.id
|
||||
const spRows = allSeasonParticipants.filter((sp) =>
|
||||
incoming.some((r) => r.participantId === sp.id),
|
||||
);
|
||||
const missingCanonical = spRows.filter((sp) => !sp.participantId);
|
||||
if (missingCanonical.length > 0) {
|
||||
return {
|
||||
error: `Some season participants are not linked to canonical participants: ${missingCanonical.map((sp) => sp.name).join(", ")}`,
|
||||
};
|
||||
}
|
||||
|
||||
for (const row of incoming) {
|
||||
const sp = spRows.find((s) => s.id === row.participantId);
|
||||
if (!sp?.participantId) continue;
|
||||
await upsertTournamentResult({
|
||||
tournamentId: scoringEvent.tournamentId,
|
||||
participantId: sp.participantId,
|
||||
placement: row.placement,
|
||||
});
|
||||
}
|
||||
|
||||
const syncReport = await syncTournamentResults(scoringEvent.tournamentId);
|
||||
return {
|
||||
success: `${incoming.length} result${incoming.length === 1 ? "" : "s"} saved canonically. Synced to ${syncReport.windowsSynced} window${syncReport.windowsSynced === 1 ? "" : "s"}${syncReport.windowsFailed > 0 ? ` (${syncReport.windowsFailed} failed)` : ""}.`,
|
||||
syncReport,
|
||||
};
|
||||
}
|
||||
|
||||
// Legacy direct-write path for non-canonical events (team sports, etc.).
|
||||
const existingResults = await getEventResults(params.eventId);
|
||||
const existingIds = new Set(existingResults.map((r) => r.seasonParticipantId));
|
||||
const newResults = filterNewResults(incoming, existingIds);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue