import { database } from "~/database/context"; import * as schema from "~/database/schema"; import { eq, and, inArray, desc } from "drizzle-orm"; export interface UpsertSeasonResultData { participantId: string; sportsSeasonId: string; currentPoints?: number; currentPosition?: number; } export interface UpdateSeasonResultData { currentPoints?: number; currentPosition?: number; } /** * Upsert a participant's season result (for F1, etc.) * Creates if doesn't exist, updates if it does */ export async function upsertParticipantSeasonResult( data: UpsertSeasonResultData, providedDb?: ReturnType ) { const db = providedDb || database(); // Check if result exists const existing = await db.query.participantSeasonResults.findFirst({ where: and( eq(schema.participantSeasonResults.participantId, data.participantId), eq(schema.participantSeasonResults.sportsSeasonId, data.sportsSeasonId) ), }); if (existing) { // Update existing const [updated] = await db .update(schema.participantSeasonResults) .set({ currentPoints: data.currentPoints?.toString(), currentPosition: data.currentPosition, updatedAt: new Date(), }) .where(eq(schema.participantSeasonResults.id, existing.id)) .returning(); return updated; } else { // Insert new const [created] = await db .insert(schema.participantSeasonResults) .values({ participantId: data.participantId, sportsSeasonId: data.sportsSeasonId, currentPoints: data.currentPoints?.toString() || "0", currentPosition: data.currentPosition, }) .returning(); return created; } } /** * Bulk upsert season results for multiple participants * Useful for entering standings for an entire F1 grid at once */ export async function upsertSeasonResultsBulk( results: UpsertSeasonResultData[], providedDb?: ReturnType ) { const db = providedDb || database(); const upserted = []; for (const data of results) { const result = await upsertParticipantSeasonResult(data, db); upserted.push(result); } return upserted; } /** * Get a participant's season result */ export async function getParticipantSeasonResult( participantId: string, sportsSeasonId: string, providedDb?: ReturnType ) { const db = providedDb || database(); return await db.query.participantSeasonResults.findFirst({ where: and( eq(schema.participantSeasonResults.participantId, participantId), eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId) ), with: { participant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, }, }); } /** * Get all season results for a sports season * Returns participants ordered by current position (or points if position not set) */ export async function getSeasonResults( sportsSeasonId: string, providedDb?: ReturnType ) { const db = providedDb || database(); const results = await db.query.participantSeasonResults.findMany({ where: eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId), with: { participant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, }, }); // Sort by position (nulls last), then by points descending return results.sort((a, b) => { if (a.currentPosition !== null && b.currentPosition !== null) { return a.currentPosition - b.currentPosition; } if (a.currentPosition !== null) return -1; if (b.currentPosition !== null) return 1; // Both null positions, sort by points const aPoints = parseFloat(a.currentPoints || "0"); const bPoints = parseFloat(b.currentPoints || "0"); return bPoints - aPoints; }); } /** * Get season results for specific participants */ export async function getSeasonResultsForParticipants( sportsSeasonId: string, participantIds: string[], providedDb?: ReturnType ) { const db = providedDb || database(); if (participantIds.length === 0) return []; return await db.query.participantSeasonResults.findMany({ where: and( eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId), inArray(schema.participantSeasonResults.participantId, participantIds) ), with: { participant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, }, }); } /** * Update a participant's season result */ export async function updateParticipantSeasonResult( participantId: string, sportsSeasonId: string, data: UpdateSeasonResultData, providedDb?: ReturnType ) { const db = providedDb || database(); const [updated] = await db .update(schema.participantSeasonResults) .set({ currentPoints: data.currentPoints?.toString(), currentPosition: data.currentPosition, updatedAt: new Date(), }) .where( and( eq(schema.participantSeasonResults.participantId, participantId), eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId) ) ) .returning(); return updated; } /** * Delete all season results for a sports season */ export async function deleteSeasonResults( sportsSeasonId: string, providedDb?: ReturnType ) { const db = providedDb || database(); await db .delete(schema.participantSeasonResults) .where(eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId)); } /** * Check if a participant has a season result */ export async function hasParticipantSeasonResult( participantId: string, sportsSeasonId: string, providedDb?: ReturnType ): Promise { const db = providedDb || database(); const result = await db.query.participantSeasonResults.findFirst({ where: and( eq(schema.participantSeasonResults.participantId, participantId), eq(schema.participantSeasonResults.sportsSeasonId, sportsSeasonId) ), }); return !!result; }