Migrate participant_golf_skills from per-season to canonical table (one row per real-world player), mirroring the existing participant_surface_elos pattern. Adds admin UI to copy participants between same-sport seasons with EV stubs, transactional writes, and comprehensive tests.
42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import { eq } from "drizzle-orm";
|
|
import { database } from "~/database/context";
|
|
import * as schema from "~/database/schema";
|
|
|
|
export type CanonicalGolfSkills = typeof schema.participantGolfSkills.$inferSelect;
|
|
export type NewCanonicalGolfSkills = typeof schema.participantGolfSkills.$inferInsert;
|
|
|
|
export async function upsertCanonicalGolfSkills(
|
|
data: NewCanonicalGolfSkills,
|
|
): Promise<CanonicalGolfSkills> {
|
|
if (!data.participantId) {
|
|
throw new Error("participantId is required");
|
|
}
|
|
|
|
const db = database();
|
|
const [result] = await db
|
|
.insert(schema.participantGolfSkills)
|
|
.values(data)
|
|
.onConflictDoUpdate({
|
|
target: [schema.participantGolfSkills.participantId],
|
|
set: {
|
|
sgTotal: data.sgTotal,
|
|
datagolfRank: data.datagolfRank,
|
|
mastersOdds: data.mastersOdds,
|
|
usOpenOdds: data.usOpenOdds,
|
|
openChampionshipOdds: data.openChampionshipOdds,
|
|
pgaChampionshipOdds: data.pgaChampionshipOdds,
|
|
updatedAt: new Date(),
|
|
},
|
|
})
|
|
.returning();
|
|
return result;
|
|
}
|
|
|
|
export async function getCanonicalGolfSkills(
|
|
participantId: string,
|
|
): Promise<CanonicalGolfSkills | null> {
|
|
const db = database();
|
|
return await db.query.participantGolfSkills.findFirst({
|
|
where: eq(schema.participantGolfSkills.participantId, participantId),
|
|
}) ?? null;
|
|
}
|