brackt/app/models/event-result.ts
Claude 6fbeef2917
Add notParticipating flag to allow excluding withdrawn participants from qualifying-points simulators
Adds a `not_participating` boolean column to `event_results` so admins can
mark a participant as not competing in a specific upcoming major (e.g. Alcaraz
withdrawing from Wimbledon due to injury). The golf, tennis, and CS2 major
simulators now query this flag for incomplete events and exclude those
participants from the event's draw/field, redistributing probability weight
to the remaining field. Admin UI for qualifying major_tournament events gains
a "Not Participating" card to mark/unmark withdrawals before the event runs.

https://claude.ai/code/session_01HxNPLEXzr5Km3suWrJe2F9
2026-05-19 17:33:32 +00:00

269 lines
6.4 KiB
TypeScript

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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
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<typeof database>
) {
const db = providedDb || database();
await db
.delete(schema.eventResults)
.where(eq(schema.eventResults.scoringEventId, eventId));
}
/**
* Check if a participant has a result for a specific event
*/
export async function hasParticipantResult(
eventId: string,
participantId: string,
providedDb?: ReturnType<typeof database>
): Promise<boolean> {
const db = providedDb || database();
const result = await db.query.eventResults.findFirst({
where: and(
eq(schema.eventResults.scoringEventId, eventId),
eq(schema.eventResults.seasonParticipantId, participantId)
),
});
return !!result;
}
/**
* 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<typeof database>
): 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<typeof database>
) {
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,
},
},
},
},
},
});
}