import { database } from "~/database/context"; import * as schema from "~/database/schema"; import { eq, and, inArray } from "drizzle-orm"; export interface CreateEventResultData { scoringEventId: string; participantId: string; placement?: number; qualifyingPointsAwarded?: number; eliminated?: boolean; rawScore?: number; notParticipating?: boolean; } export interface UpdateEventResultData { placement?: number; qualifyingPointsAwarded?: number; eliminated?: boolean; rawScore?: number; notParticipating?: boolean; } /** * Create an event result for a participant */ export async function createEventResult( data: CreateEventResultData, providedDb?: ReturnType ) { const db = providedDb || database(); const [result] = await db .insert(schema.eventResults) .values({ scoringEventId: data.scoringEventId, seasonParticipantId: data.participantId, placement: data.placement, qualifyingPointsAwarded: data.qualifyingPointsAwarded?.toString(), eliminated: data.eliminated, rawScore: data.rawScore?.toString(), notParticipating: data.notParticipating, }) .returning(); return result; } /** * Create multiple event results in bulk * Useful for entering all results for a tournament at once */ export async function createEventResultsBulk( results: CreateEventResultData[], providedDb?: ReturnType ) { const db = providedDb || database(); const inserted = await db .insert(schema.eventResults) .values( results.map((r) => ({ scoringEventId: r.scoringEventId, seasonParticipantId: r.participantId, placement: r.placement, qualifyingPointsAwarded: r.qualifyingPointsAwarded?.toString(), eliminated: r.eliminated, rawScore: r.rawScore?.toString(), notParticipating: r.notParticipating, })) ) .returning(); return inserted; } /** * Get an event result by ID */ export async function getEventResultById( resultId: string, providedDb?: ReturnType ) { const db = providedDb || database(); return await db.query.eventResults.findFirst({ where: eq(schema.eventResults.id, resultId), with: { seasonParticipant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, scoringEvent: true, }, }); } /** * Get all results for a scoring event */ export async function getEventResults( eventId: string, providedDb?: ReturnType ) { const db = providedDb || database(); return await db.query.eventResults.findMany({ where: eq(schema.eventResults.scoringEventId, eventId), orderBy: schema.eventResults.placement, with: { seasonParticipant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, }, }); } /** * Get all event results for a participant across all events */ export async function getParticipantEventResults( participantId: string, providedDb?: ReturnType ) { const db = providedDb || database(); return await db.query.eventResults.findMany({ where: eq(schema.eventResults.seasonParticipantId, participantId), with: { scoringEvent: true, }, orderBy: schema.eventResults.createdAt, }); } /** * Update an event result */ export async function updateEventResult( resultId: string, data: UpdateEventResultData, providedDb?: ReturnType ) { const db = providedDb || database(); const [updated] = await db .update(schema.eventResults) .set({ placement: data.placement, qualifyingPointsAwarded: data.qualifyingPointsAwarded?.toString(), eliminated: data.eliminated, rawScore: data.rawScore?.toString(), notParticipating: data.notParticipating, updatedAt: new Date(), }) .where(eq(schema.eventResults.id, resultId)) .returning(); return updated; } /** * Delete an event result */ export async function deleteEventResult( resultId: string, providedDb?: ReturnType ) { const db = providedDb || database(); await db.delete(schema.eventResults).where(eq(schema.eventResults.id, resultId)); } /** * Delete all results for a scoring event */ export async function deleteEventResults( eventId: string, providedDb?: ReturnType ) { const db = providedDb || database(); await db .delete(schema.eventResults) .where(eq(schema.eventResults.scoringEventId, eventId)); } /** * Check if a participant has a real result (placement/QP) for a specific event. * Returns false for not-participating rows, which are exclusion markers, not results. */ export async function hasParticipantResult( eventId: string, participantId: string, providedDb?: ReturnType ): Promise { const db = providedDb || database(); const result = await db.query.eventResults.findFirst({ where: and( eq(schema.eventResults.scoringEventId, eventId), eq(schema.eventResults.seasonParticipantId, participantId), eq(schema.eventResults.notParticipating, false) ), }); return !!result; } /** * Build a map of eventId → Set for all not-participating rows * across a list of scoring events. Used by qualifying-points simulators to * exclude withdrawn participants from each event's draw/pool in a single query. */ export async function getExcludedByEventMap( eventIds: string[], providedDb?: ReturnType ): Promise>> { if (eventIds.length === 0) return new Map(); const db = providedDb || database(); const rows = await db .select({ scoringEventId: schema.eventResults.scoringEventId, seasonParticipantId: schema.eventResults.seasonParticipantId, }) .from(schema.eventResults) .where( and( inArray(schema.eventResults.scoringEventId, eventIds), eq(schema.eventResults.notParticipating, true) ) ); const map = new Map>(); for (const r of rows) { let set = map.get(r.scoringEventId); if (!set) { set = new Set(); map.set(r.scoringEventId, set); } set.add(r.seasonParticipantId); } return map; } /** * Get all not-participating records for a scoring event. * Used by simulators to exclude withdrawn participants from future event draws. */ export async function getNotParticipatingResults( eventId: string, providedDb?: ReturnType ): Promise<{ seasonParticipantId: string }[]> { const db = providedDb || database(); return await db .select({ seasonParticipantId: schema.eventResults.seasonParticipantId }) .from(schema.eventResults) .where( and( eq(schema.eventResults.scoringEventId, eventId), eq(schema.eventResults.notParticipating, true) ) ); } /** * Get results for multiple participants in a specific event * Useful for checking drafted participants' performance */ export async function getEventResultsForParticipants( eventId: string, participantIds: string[], providedDb?: ReturnType ) { const db = providedDb || database(); if (participantIds.length === 0) return []; return await db.query.eventResults.findMany({ where: and( eq(schema.eventResults.scoringEventId, eventId), inArray(schema.eventResults.seasonParticipantId, participantIds) ), with: { seasonParticipant: { with: { sportsSeason: { with: { sport: true, }, }, }, }, }, }); }