204 lines
5.1 KiB
TypeScript
204 lines
5.1 KiB
TypeScript
import { database } from "~/database/context";
|
|
import * as schema from "~/database/schema";
|
|
import { eq, and, desc } from "drizzle-orm";
|
|
|
|
export type EventType = "playoff_game" | "major_tournament" | "final_standings";
|
|
|
|
export interface CreateScoringEventData {
|
|
sportsSeasonId: string;
|
|
name: string;
|
|
eventDate?: Date;
|
|
eventType: EventType;
|
|
isQualifyingEvent?: boolean;
|
|
// Template system fields (Phase 2.6)
|
|
bracketTemplateId?: string;
|
|
scoringStartsAtRound?: string;
|
|
}
|
|
|
|
export interface UpdateScoringEventData {
|
|
name?: string;
|
|
eventDate?: Date;
|
|
isComplete?: boolean;
|
|
completedAt?: Date;
|
|
bracketTemplateId?: string;
|
|
scoringStartsAtRound?: string;
|
|
}
|
|
|
|
/**
|
|
* Create a new scoring event
|
|
*/
|
|
export async function createScoringEvent(
|
|
data: CreateScoringEventData,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
const [event] = await db
|
|
.insert(schema.scoringEvents)
|
|
.values({
|
|
sportsSeasonId: data.sportsSeasonId,
|
|
name: data.name,
|
|
eventDate: data.eventDate ? data.eventDate.toISOString().split('T')[0] : undefined,
|
|
eventType: data.eventType,
|
|
isQualifyingEvent: data.isQualifyingEvent || false,
|
|
bracketTemplateId: data.bracketTemplateId,
|
|
scoringStartsAtRound: data.scoringStartsAtRound,
|
|
isComplete: false,
|
|
})
|
|
.returning();
|
|
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* Get a scoring event by ID
|
|
*/
|
|
export async function getScoringEventById(
|
|
eventId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
return await db.query.scoringEvents.findFirst({
|
|
where: eq(schema.scoringEvents.id, eventId),
|
|
with: {
|
|
sportsSeason: {
|
|
with: {
|
|
sport: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all scoring events for a sports season
|
|
*/
|
|
export async function getScoringEventsForSportsSeason(
|
|
sportsSeasonId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
return await db.query.scoringEvents.findMany({
|
|
where: eq(schema.scoringEvents.sportsSeasonId, sportsSeasonId),
|
|
orderBy: [desc(schema.scoringEvents.eventDate), desc(schema.scoringEvents.createdAt)],
|
|
with: {
|
|
eventResults: {
|
|
with: {
|
|
participant: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get incomplete scoring events for a sports season
|
|
*/
|
|
export async function getIncompleteScoringEvents(
|
|
sportsSeasonId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
return await db.query.scoringEvents.findMany({
|
|
where: and(
|
|
eq(schema.scoringEvents.sportsSeasonId, sportsSeasonId),
|
|
eq(schema.scoringEvents.isComplete, false)
|
|
),
|
|
orderBy: [desc(schema.scoringEvents.eventDate), desc(schema.scoringEvents.createdAt)],
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get qualifying events for a sports season
|
|
*/
|
|
export async function getQualifyingEvents(
|
|
sportsSeasonId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
return await db.query.scoringEvents.findMany({
|
|
where: and(
|
|
eq(schema.scoringEvents.sportsSeasonId, sportsSeasonId),
|
|
eq(schema.scoringEvents.isQualifyingEvent, true)
|
|
),
|
|
orderBy: [desc(schema.scoringEvents.eventDate), desc(schema.scoringEvents.createdAt)],
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update a scoring event
|
|
*/
|
|
export async function updateScoringEvent(
|
|
eventId: string,
|
|
data: UpdateScoringEventData,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
const updateData: any = { updatedAt: new Date() };
|
|
|
|
if (data.name !== undefined) updateData.name = data.name;
|
|
if (data.eventDate !== undefined) {
|
|
updateData.eventDate = data.eventDate.toISOString().split('T')[0];
|
|
}
|
|
if (data.isComplete !== undefined) updateData.isComplete = data.isComplete;
|
|
if (data.completedAt !== undefined) updateData.completedAt = data.completedAt;
|
|
if (data.bracketTemplateId !== undefined) updateData.bracketTemplateId = data.bracketTemplateId;
|
|
if (data.scoringStartsAtRound !== undefined) updateData.scoringStartsAtRound = data.scoringStartsAtRound;
|
|
|
|
const [updated] = await db
|
|
.update(schema.scoringEvents)
|
|
.set(updateData)
|
|
.where(eq(schema.scoringEvents.id, eventId))
|
|
.returning();
|
|
|
|
return updated;
|
|
}
|
|
|
|
/**
|
|
* Mark a scoring event as complete
|
|
*/
|
|
export async function completeScoringEvent(
|
|
eventId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
return await updateScoringEvent(
|
|
eventId,
|
|
{
|
|
isComplete: true,
|
|
completedAt: new Date(),
|
|
},
|
|
db
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete a scoring event
|
|
*/
|
|
export async function deleteScoringEvent(
|
|
eventId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
) {
|
|
const db = providedDb || database();
|
|
|
|
await db.delete(schema.scoringEvents).where(eq(schema.scoringEvents.id, eventId));
|
|
}
|
|
|
|
/**
|
|
* Check if all events for a sports season are complete
|
|
*/
|
|
export async function areAllEventsComplete(
|
|
sportsSeasonId: string,
|
|
providedDb?: ReturnType<typeof database>
|
|
): Promise<boolean> {
|
|
const db = providedDb || database();
|
|
|
|
const incompleteEvents = await getIncompleteScoringEvents(sportsSeasonId, db);
|
|
return incompleteEvents.length === 0;
|
|
}
|