brackt/app/models/canonical-surface-elo.ts
Chris Parsons 5a47300110
feat(models): add canonical tournament, participant, result, surface-elo models
Adds CRUD modules for the canonical tables created in commit 775b905.
Each module mirrors existing app/models conventions (database() from
~/database/context, schema from ~/database/schema, mock-based tests).

Key implementation notes:
- participant.ts exports use "Canonical" prefix (CanonicalParticipant,
  createCanonicalParticipant, etc.) to avoid collision with existing
  season-participant.ts exports
- All four models include comprehensive unit tests following the
  audit-log.test.ts pattern
- Tests use mocked db responses (no real database access)
- Upsert functions use onConflictDoUpdate for appropriate unique constraints

Part of Phase 1b of canonical tournament layer migration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:16:53 +00:00

43 lines
1.2 KiB
TypeScript

import { eq } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
export type CanonicalSurfaceElo = typeof schema.participantSurfaceElos.$inferSelect;
export type NewCanonicalSurfaceElo = typeof schema.participantSurfaceElos.$inferInsert;
export async function upsertCanonicalSurfaceElo(
data: NewCanonicalSurfaceElo
): Promise<CanonicalSurfaceElo> {
if (!data.participantId) {
throw new Error("participantId is required");
}
const db = database();
const [result] = await db
.insert(schema.participantSurfaceElos)
.values(data)
.onConflictDoUpdate({
target: [schema.participantSurfaceElos.participantId],
set: {
worldRanking: data.worldRanking,
eloHard: data.eloHard,
eloClay: data.eloClay,
eloGrass: data.eloGrass,
updatedAt: new Date(),
},
})
.returning();
return result;
}
export async function getCanonicalSurfaceElo(
participantId: string
): Promise<CanonicalSurfaceElo | null> {
const db = database();
const results = await db
.select()
.from(schema.participantSurfaceElos)
.where(eq(schema.participantSurfaceElos.participantId, participantId))
.limit(1);
return results[0] ?? null;
}