Adds a sports_season_tournaments junction table and bidirectional link/unlink UI on both the sports season and tournament admin pages. - New junction table with unique index on (sports_season_id, tournament_id) and a separate index on tournament_id for reverse lookups - New model with link/unlink/query functions and cross-sport validation - Migration includes backfill from existing scoring_events tournament links - Admin sports season page: Tournaments card with add/remove UI - Admin tournament page: Linked Sports Seasons card with add/remove UI - Inline success/error feedback, empty states, aria-labels on remove buttons - cloneSportsSeason now copies tournament links - Fixes darts simulator test timeout (15s for 128-player pre-bracket sim)
74 lines
2.2 KiB
TypeScript
74 lines
2.2 KiB
TypeScript
import { eq, and } from "drizzle-orm";
|
|
import { database } from "~/database/context";
|
|
import * as schema from "~/database/schema";
|
|
import { getTournamentById } from "./tournament";
|
|
import { findSportsSeasonById } from "./sports-season";
|
|
|
|
export type SportsSeasonTournament = typeof schema.sportsSeasonTournaments.$inferSelect;
|
|
export type NewSportsSeasonTournament = typeof schema.sportsSeasonTournaments.$inferInsert;
|
|
|
|
export async function linkTournamentToSportsSeason(
|
|
sportsSeasonId: string,
|
|
tournamentId: string
|
|
): Promise<SportsSeasonTournament> {
|
|
const [sportsSeason, tournament] = await Promise.all([
|
|
findSportsSeasonById(sportsSeasonId),
|
|
getTournamentById(tournamentId),
|
|
]);
|
|
|
|
if (!sportsSeason) {
|
|
throw new Error(`Sports season ${sportsSeasonId} not found`);
|
|
}
|
|
if (!tournament) {
|
|
throw new Error(`Tournament ${tournamentId} not found`);
|
|
}
|
|
if (sportsSeason.sportId !== tournament.sportId) {
|
|
throw new Error("Tournament and sports season must belong to the same sport");
|
|
}
|
|
|
|
const db = database();
|
|
const [link] = await db
|
|
.insert(schema.sportsSeasonTournaments)
|
|
.values({ sportsSeasonId, tournamentId })
|
|
.returning();
|
|
return link;
|
|
}
|
|
|
|
export async function unlinkTournamentFromSportsSeason(
|
|
sportsSeasonId: string,
|
|
tournamentId: string
|
|
): Promise<void> {
|
|
const db = database();
|
|
await db
|
|
.delete(schema.sportsSeasonTournaments)
|
|
.where(
|
|
and(
|
|
eq(schema.sportsSeasonTournaments.sportsSeasonId, sportsSeasonId),
|
|
eq(schema.sportsSeasonTournaments.tournamentId, tournamentId)
|
|
)
|
|
);
|
|
}
|
|
|
|
export async function findTournamentsBySportsSeason(sportsSeasonId: string) {
|
|
const db = database();
|
|
return await db.query.sportsSeasonTournaments.findMany({
|
|
where: eq(schema.sportsSeasonTournaments.sportsSeasonId, sportsSeasonId),
|
|
with: {
|
|
tournament: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function findSportsSeasonsByTournament(tournamentId: string) {
|
|
const db = database();
|
|
return await db.query.sportsSeasonTournaments.findMany({
|
|
where: eq(schema.sportsSeasonTournaments.tournamentId, tournamentId),
|
|
with: {
|
|
sportsSeason: {
|
|
with: {
|
|
sport: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|