feat(surface-elo): mirror batchUpsert writes to canonical table
The simulator now reads surface Elo from the canonical table (participant_surface_elos). The existing per-window admin page still posts to batchUpsertSurfaceElos; without this change, those edits would silently fail to affect simulator output. Mirror every write to both tables until Phase 4 removes the per-window path entirely. Phase 3 Task 5 (partial — canonical write path; dedicated canonical admin UI deferred; existing page continues to work and now edits both tables). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
3e81dfe8da
commit
7483cd628b
1 changed files with 40 additions and 1 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import { database } from "~/database/context";
|
import { database } from "~/database/context";
|
||||||
import { participantSurfaceElos, seasonParticipantSurfaceElos, seasonParticipants } from "~/database/schema";
|
import { participantSurfaceElos, seasonParticipantSurfaceElos, seasonParticipants } from "~/database/schema";
|
||||||
import { eq, sql } from "drizzle-orm";
|
import { eq, inArray, sql } from "drizzle-orm";
|
||||||
|
|
||||||
export type CourtSurface = "hard" | "clay" | "grass";
|
export type CourtSurface = "hard" | "clay" | "grass";
|
||||||
|
|
||||||
|
|
@ -99,6 +99,45 @@ export async function batchUpsertSurfaceElos(
|
||||||
updatedAt: sql`excluded.updated_at`,
|
updatedAt: sql`excluded.updated_at`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mirror writes to the canonical participant_surface_elos table.
|
||||||
|
// The simulator reads from canonical, so per-window-only edits would
|
||||||
|
// not affect simulations. Remove the per-window path entirely in Phase 4.
|
||||||
|
const sps = await db
|
||||||
|
.select({ id: seasonParticipants.id, canonicalId: seasonParticipants.participantId })
|
||||||
|
.from(seasonParticipants)
|
||||||
|
.where(inArray(seasonParticipants.id, inputs.map((i) => i.participantId)));
|
||||||
|
const canonicalByInputId = new Map(sps.map((sp) => [sp.id, sp.canonicalId]));
|
||||||
|
|
||||||
|
const canonicalRows = inputs
|
||||||
|
.map((i) => ({
|
||||||
|
canonicalId: canonicalByInputId.get(i.participantId),
|
||||||
|
worldRanking: i.worldRanking ?? null,
|
||||||
|
eloHard: i.eloHard ?? null,
|
||||||
|
eloClay: i.eloClay ?? null,
|
||||||
|
eloGrass: i.eloGrass ?? null,
|
||||||
|
}))
|
||||||
|
.filter((r): r is typeof r & { canonicalId: string } => typeof r.canonicalId === "string");
|
||||||
|
|
||||||
|
if (canonicalRows.length === 0) return;
|
||||||
|
|
||||||
|
await db
|
||||||
|
.insert(participantSurfaceElos)
|
||||||
|
.values(canonicalRows.map(({ canonicalId, ...rest }) => ({
|
||||||
|
participantId: canonicalId,
|
||||||
|
...rest,
|
||||||
|
updatedAt: now,
|
||||||
|
})))
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [participantSurfaceElos.participantId],
|
||||||
|
set: {
|
||||||
|
worldRanking: sql`excluded.world_ranking`,
|
||||||
|
eloHard: sql`excluded.elo_hard`,
|
||||||
|
eloClay: sql`excluded.elo_clay`,
|
||||||
|
eloGrass: sql`excluded.elo_grass`,
|
||||||
|
updatedAt: sql`excluded.updated_at`,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue