brackt/app/models/season-match.ts

233 lines
7.3 KiB
TypeScript
Raw Normal View History

import { and, asc, eq, isNotNull, sql } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
export type SeasonMatch = typeof schema.seasonMatches.$inferSelect;
export type MatchSubGame = typeof schema.matchSubGames.$inferSelect;
export type MatchStatus = (typeof schema.matchStatusEnum.enumValues)[number];
export interface UpsertSeasonMatchData {
sportsSeasonId: string;
scoringEventId?: string | null;
participant1Id?: string | null;
participant2Id?: string | null;
winnerId?: string | null;
participant1Score?: number | null;
participant2Score?: number | null;
matchStage?: number | null;
matchRound?: number | null;
matchday?: number | null;
isSeries?: boolean;
status: MatchStatus;
scheduledAt?: Date | null;
startedAt?: Date | null;
completedAt?: Date | null;
externalMatchId: string;
}
export interface UpsertMatchSubGameData {
seasonMatchId: string;
gameNumber: number;
gameLabel?: string | null;
participant1Score?: number | null;
participant2Score?: number | null;
winnerId?: string | null;
status: MatchStatus;
startedAt?: Date | null;
completedAt?: Date | null;
externalGameId?: string | null;
}
export async function upsertSeasonMatch(
data: UpsertSeasonMatchData
): Promise<SeasonMatch> {
const db = database();
const now = new Date();
const [result] = await db
.insert(schema.seasonMatches)
.values({
...data,
isSeries: data.isSeries ?? false,
updatedAt: now,
})
.onConflictDoUpdate({
target: schema.seasonMatches.externalMatchId,
targetWhere: isNotNull(schema.seasonMatches.externalMatchId),
set: {
participant1Id: sql`excluded.participant1_id`,
participant2Id: sql`excluded.participant2_id`,
winnerId: sql`excluded.winner_id`,
participant1Score: sql`excluded.participant1_score`,
participant2Score: sql`excluded.participant2_score`,
matchStage: sql`excluded.match_stage`,
matchRound: sql`excluded.match_round`,
matchday: sql`excluded.matchday`,
isSeries: sql`excluded.is_series`,
status: sql`excluded.status`,
scheduledAt: sql`excluded.scheduled_at`,
startedAt: sql`excluded.started_at`,
completedAt: sql`excluded.completed_at`,
updatedAt: now,
},
})
.returning();
return result;
}
export async function upsertSeasonMatchBulk(
records: UpsertSeasonMatchData[]
): Promise<SeasonMatch[]> {
if (records.length === 0) return [];
const db = database();
const now = new Date();
return await db
.insert(schema.seasonMatches)
.values(records.map((r) => ({ ...r, isSeries: r.isSeries ?? false, updatedAt: now })))
.onConflictDoUpdate({
target: schema.seasonMatches.externalMatchId,
targetWhere: isNotNull(schema.seasonMatches.externalMatchId),
set: {
participant1Id: sql`excluded.participant1_id`,
participant2Id: sql`excluded.participant2_id`,
winnerId: sql`excluded.winner_id`,
participant1Score: sql`excluded.participant1_score`,
participant2Score: sql`excluded.participant2_score`,
matchStage: sql`excluded.match_stage`,
matchRound: sql`excluded.match_round`,
matchday: sql`excluded.matchday`,
isSeries: sql`excluded.is_series`,
status: sql`excluded.status`,
scheduledAt: sql`excluded.scheduled_at`,
startedAt: sql`excluded.started_at`,
completedAt: sql`excluded.completed_at`,
updatedAt: now,
},
})
.returning();
}
export async function findSeasonMatchesBySportsSeasonId(
sportsSeasonId: string,
filters?: { status?: MatchStatus; matchStage?: number }
) {
const db = database();
return await db.query.seasonMatches.findMany({
where: and(
eq(schema.seasonMatches.sportsSeasonId, sportsSeasonId),
filters?.status ? eq(schema.seasonMatches.status, filters.status) : undefined,
filters?.matchStage !== undefined
? eq(schema.seasonMatches.matchStage, filters.matchStage)
: undefined
),
orderBy: [
asc(schema.seasonMatches.matchStage),
asc(schema.seasonMatches.matchRound),
asc(schema.seasonMatches.matchday),
asc(schema.seasonMatches.scheduledAt),
asc(schema.seasonMatches.createdAt),
],
with: {
participant1: true,
participant2: true,
winner: true,
subGames: { orderBy: [asc(schema.matchSubGames.gameNumber)] },
},
});
}
export async function findSeasonMatchesByScoringEventId(scoringEventId: string) {
const db = database();
return await db.query.seasonMatches.findMany({
where: eq(schema.seasonMatches.scoringEventId, scoringEventId),
orderBy: [
asc(schema.seasonMatches.matchStage),
asc(schema.seasonMatches.matchRound),
asc(schema.seasonMatches.scheduledAt),
asc(schema.seasonMatches.createdAt),
],
with: {
participant1: true,
participant2: true,
winner: true,
subGames: { orderBy: [asc(schema.matchSubGames.gameNumber)] },
},
});
}
export async function findSeasonMatchById(matchId: string) {
const db = database();
return await db.query.seasonMatches.findFirst({
where: eq(schema.seasonMatches.id, matchId),
with: {
participant1: true,
participant2: true,
winner: true,
subGames: { orderBy: [asc(schema.matchSubGames.gameNumber)] },
},
});
}
export async function updateSeasonMatch(
matchId: string,
data: Partial<{
participant1Id: string | null;
participant2Id: string | null;
winnerId: string | null;
participant1Score: number | null;
participant2Score: number | null;
status: MatchStatus;
scheduledAt: Date | null;
startedAt: Date | null;
completedAt: Date | null;
}>
): Promise<SeasonMatch> {
const db = database();
const [result] = await db
.update(schema.seasonMatches)
.set({ ...data, updatedAt: new Date() })
.where(eq(schema.seasonMatches.id, matchId))
.returning();
return result;
}
export async function deleteSeasonMatch(matchId: string): Promise<void> {
const db = database();
await db
.delete(schema.seasonMatches)
.where(eq(schema.seasonMatches.id, matchId));
}
export async function upsertMatchSubGame(
data: UpsertMatchSubGameData
): Promise<MatchSubGame> {
const db = database();
const now = new Date();
const [result] = await db
.insert(schema.matchSubGames)
.values({ ...data, updatedAt: now })
.onConflictDoUpdate({
target: [schema.matchSubGames.seasonMatchId, schema.matchSubGames.gameNumber],
set: {
gameLabel: sql`excluded.game_label`,
participant1Score: sql`excluded.participant1_score`,
participant2Score: sql`excluded.participant2_score`,
winnerId: sql`excluded.winner_id`,
status: sql`excluded.status`,
startedAt: sql`excluded.started_at`,
completedAt: sql`excluded.completed_at`,
externalGameId: sql`excluded.external_game_id`,
updatedAt: now,
},
})
.returning();
return result;
}
export async function findMatchSubGamesByMatchId(matchId: string): Promise<MatchSubGame[]> {
const db = database();
return await db.query.matchSubGames.findMany({
where: eq(schema.matchSubGames.seasonMatchId, matchId),
orderBy: [asc(schema.matchSubGames.gameNumber)],
});
}