186 lines
4.6 KiB
TypeScript
186 lines
4.6 KiB
TypeScript
import { eq, and } from "drizzle-orm";
|
|
import { database } from "~/database/context";
|
|
import * as schema from "~/database/schema";
|
|
|
|
export type Season = typeof schema.seasons.$inferSelect;
|
|
export type NewSeason = Omit<typeof schema.seasons.$inferInsert, 'inviteCode'> & {
|
|
inviteCode?: string;
|
|
};
|
|
export type SeasonStatus = "pre_draft" | "draft" | "active" | "completed";
|
|
|
|
export interface SeasonWithSportsSeasons extends Season {
|
|
seasonSports: Array<{
|
|
id: string;
|
|
sportsSeason: {
|
|
id: string;
|
|
name: string;
|
|
year: number;
|
|
status: string;
|
|
scoringType: string;
|
|
sport: {
|
|
id: string;
|
|
name: string;
|
|
type: string;
|
|
slug: string;
|
|
};
|
|
};
|
|
}>;
|
|
}
|
|
|
|
export async function createSeason(data: NewSeason): Promise<Season> {
|
|
const db = database();
|
|
|
|
// Generate invite code if not provided
|
|
const seasonData = {
|
|
...data,
|
|
inviteCode: data.inviteCode || generateInviteCode(),
|
|
};
|
|
|
|
const [season] = await db
|
|
.insert(schema.seasons)
|
|
.values(seasonData)
|
|
.returning();
|
|
return season;
|
|
}
|
|
|
|
export async function findSeasonById(id: string): Promise<Season | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: eq(schema.seasons.id, id),
|
|
});
|
|
}
|
|
|
|
export async function findSeasonsByLeagueId(leagueId: string): Promise<Season[]> {
|
|
const db = database();
|
|
return await db.query.seasons.findMany({
|
|
where: eq(schema.seasons.leagueId, leagueId),
|
|
orderBy: (seasons, { desc }) => [desc(seasons.year)],
|
|
});
|
|
}
|
|
|
|
export async function findCurrentSeason(
|
|
leagueId: string
|
|
): Promise<Season | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: eq(schema.seasons.leagueId, leagueId),
|
|
orderBy: (seasons, { desc }) => [desc(seasons.year)],
|
|
});
|
|
}
|
|
|
|
export async function findCurrentSeasonWithSports(
|
|
leagueId: string
|
|
): Promise<SeasonWithSportsSeasons | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: eq(schema.seasons.leagueId, leagueId),
|
|
orderBy: (seasons, { desc }) => [desc(seasons.year)],
|
|
with: {
|
|
seasonSports: {
|
|
with: {
|
|
sportsSeason: {
|
|
with: {
|
|
sport: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}) as SeasonWithSportsSeasons | undefined;
|
|
}
|
|
|
|
export async function findSeasonByLeagueAndYear(
|
|
leagueId: string,
|
|
year: number
|
|
): Promise<Season | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: and(
|
|
eq(schema.seasons.leagueId, leagueId),
|
|
eq(schema.seasons.year, year)
|
|
),
|
|
});
|
|
}
|
|
|
|
export async function updateSeason(
|
|
id: string,
|
|
data: Partial<NewSeason>
|
|
): Promise<Season> {
|
|
const db = database();
|
|
const [season] = await db
|
|
.update(schema.seasons)
|
|
.set({ ...data, updatedAt: new Date() })
|
|
.where(eq(schema.seasons.id, id))
|
|
.returning();
|
|
return season;
|
|
}
|
|
|
|
export async function updateSeasonStatus(
|
|
id: string,
|
|
status: SeasonStatus
|
|
): Promise<Season> {
|
|
return await updateSeason(id, { status });
|
|
}
|
|
|
|
export async function deleteSeason(id: string): Promise<void> {
|
|
const db = database();
|
|
await db.delete(schema.seasons).where(eq(schema.seasons.id, id));
|
|
}
|
|
|
|
export async function findSeasonWithSportsSeasons(
|
|
id: string
|
|
): Promise<SeasonWithSportsSeasons | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: eq(schema.seasons.id, id),
|
|
with: {
|
|
seasonSports: {
|
|
with: {
|
|
sportsSeason: {
|
|
with: {
|
|
sport: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}) as SeasonWithSportsSeasons | undefined;
|
|
}
|
|
|
|
/**
|
|
* Generate a short, URL-safe invite code
|
|
* Uses base62 encoding (alphanumeric) for readability
|
|
*/
|
|
export function generateInviteCode(): string {
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
const length = 10;
|
|
let result = '';
|
|
const randomValues = new Uint8Array(length);
|
|
crypto.getRandomValues(randomValues);
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
result += chars[randomValues[i] % chars.length];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Find a season by its invite code
|
|
*/
|
|
export async function findSeasonByInviteCode(
|
|
inviteCode: string
|
|
): Promise<Season | undefined> {
|
|
const db = database();
|
|
return await db.query.seasons.findFirst({
|
|
where: eq(schema.seasons.inviteCode, inviteCode),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Regenerate invite code for a season
|
|
*/
|
|
export async function regenerateInviteCode(seasonId: string): Promise<Season> {
|
|
const newInviteCode = generateInviteCode();
|
|
return await updateSeason(seasonId, { inviteCode: newInviteCode });
|
|
}
|