2025-10-12 21:16:00 -07:00
|
|
|
import { integer, pgTable, varchar, uuid, timestamp, pgEnum, boolean, text, date, decimal } from "drizzle-orm/pg-core";
|
|
|
|
|
import { relations } from "drizzle-orm";
|
2025-10-10 23:04:50 -07:00
|
|
|
|
2025-10-11 00:53:39 -07:00
|
|
|
// Users table - synced from Clerk
|
|
|
|
|
export const users = pgTable("users", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
clerkId: varchar("clerk_id", { length: 255 }).notNull().unique(),
|
|
|
|
|
email: varchar("email", { length: 255 }).notNull(),
|
|
|
|
|
displayName: varchar("display_name", { length: 255 }),
|
|
|
|
|
firstName: varchar("first_name", { length: 255 }),
|
|
|
|
|
lastName: varchar("last_name", { length: 255 }),
|
|
|
|
|
imageUrl: varchar("image_url", { length: 512 }),
|
2025-10-12 21:16:00 -07:00
|
|
|
isAdmin: boolean("is_admin").notNull().default(false),
|
2025-10-11 00:53:39 -07:00
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-11 00:07:39 -07:00
|
|
|
// Fantasy League Tables
|
|
|
|
|
export const seasonStatusEnum = pgEnum("season_status", [
|
|
|
|
|
"pre_draft",
|
|
|
|
|
"draft",
|
|
|
|
|
"active",
|
|
|
|
|
"completed",
|
|
|
|
|
]);
|
|
|
|
|
|
2025-10-12 21:16:00 -07:00
|
|
|
// Sports Tables - Enums
|
|
|
|
|
export const sportTypeEnum = pgEnum("sport_type", ["team", "individual"]);
|
|
|
|
|
|
|
|
|
|
export const sportsSeasonStatusEnum = pgEnum("sports_season_status", [
|
|
|
|
|
"upcoming",
|
|
|
|
|
"active",
|
|
|
|
|
"completed",
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
export const scoringTypeEnum = pgEnum("scoring_type", [
|
|
|
|
|
"playoffs",
|
|
|
|
|
"regular_season",
|
|
|
|
|
"majors",
|
|
|
|
|
]);
|
|
|
|
|
|
2025-10-11 00:07:39 -07:00
|
|
|
export const leagues = pgTable("leagues", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
createdBy: varchar("created_by", { length: 255 }).notNull(), // Clerk user ID
|
2025-10-11 21:10:01 -07:00
|
|
|
currentSeasonId: uuid("current_season_id"), // References the active season
|
2025-10-11 00:07:39 -07:00
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-12 21:16:00 -07:00
|
|
|
export const seasonTemplates = pgTable("season_templates", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
description: text("description"),
|
|
|
|
|
year: integer("year").notNull(),
|
|
|
|
|
isActive: boolean("is_active").notNull().default(true),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-11 00:07:39 -07:00
|
|
|
export const seasons = pgTable("seasons", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
leagueId: uuid("league_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => leagues.id, { onDelete: "cascade" }),
|
|
|
|
|
year: integer("year").notNull(),
|
|
|
|
|
status: seasonStatusEnum("status").notNull().default("pre_draft"),
|
2025-10-12 21:16:00 -07:00
|
|
|
templateId: uuid("template_id")
|
|
|
|
|
.references(() => seasonTemplates.id, { onDelete: "set null" }),
|
|
|
|
|
flexSpots: integer("flex_spots").notNull().default(0),
|
2025-10-14 12:20:36 -07:00
|
|
|
inviteCode: varchar("invite_code", { length: 20 }).notNull().unique(),
|
2025-10-11 00:07:39 -07:00
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const teams = pgTable("teams", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
seasonId: uuid("season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => seasons.id, { onDelete: "cascade" }),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
ownerId: varchar("owner_id", { length: 255 }), // Clerk user ID, nullable
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
2025-10-11 00:29:04 -07:00
|
|
|
|
|
|
|
|
export const commissioners = pgTable("commissioners", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
leagueId: uuid("league_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => leagues.id, { onDelete: "cascade" }),
|
|
|
|
|
userId: varchar("user_id", { length: 255 }).notNull(), // Clerk user ID
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
});
|
2025-10-12 21:16:00 -07:00
|
|
|
|
|
|
|
|
// Sports Tables
|
|
|
|
|
export const sports = pgTable("sports", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
type: sportTypeEnum("type").notNull(),
|
|
|
|
|
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
|
|
|
|
description: text("description"),
|
2025-10-13 10:30:47 -07:00
|
|
|
iconUrl: varchar("icon_url", { length: 255 }), // Filename of icon in /public/sports-icons/
|
2025-10-12 21:16:00 -07:00
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const sportsSeasons = pgTable("sports_seasons", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
sportId: uuid("sport_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => sports.id, { onDelete: "cascade" }),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
year: integer("year").notNull(),
|
|
|
|
|
startDate: date("start_date"),
|
|
|
|
|
endDate: date("end_date"),
|
|
|
|
|
status: sportsSeasonStatusEnum("status").notNull().default("upcoming"),
|
|
|
|
|
scoringType: scoringTypeEnum("scoring_type").notNull(),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const participants = pgTable("participants", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
sportsSeasonId: uuid("sports_season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => sportsSeasons.id, { onDelete: "cascade" }),
|
|
|
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
|
|
|
shortName: varchar("short_name", { length: 100 }),
|
|
|
|
|
externalId: varchar("external_id", { length: 255 }),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const seasonTemplateSports = pgTable("season_template_sports", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
templateId: uuid("template_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => seasonTemplates.id, { onDelete: "cascade" }),
|
|
|
|
|
sportsSeasonId: uuid("sports_season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => sportsSeasons.id, { onDelete: "cascade" }),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const seasonSports = pgTable("season_sports", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
seasonId: uuid("season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => seasons.id, { onDelete: "cascade" }),
|
|
|
|
|
sportsSeasonId: uuid("sports_season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => sportsSeasons.id, { onDelete: "cascade" }),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const participantResults = pgTable("participant_results", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
participantId: uuid("participant_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => participants.id, { onDelete: "cascade" }),
|
|
|
|
|
sportsSeasonId: uuid("sports_season_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => sportsSeasons.id, { onDelete: "cascade" }),
|
|
|
|
|
finalPosition: integer("final_position"),
|
|
|
|
|
pointsAwarded: integer("points_awarded").notNull().default(0),
|
|
|
|
|
qualifyingPoints: decimal("qualifying_points", { precision: 10, scale: 2 }),
|
|
|
|
|
notes: text("notes"),
|
|
|
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
|
|
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Relations
|
|
|
|
|
export const sportsRelations = relations(sports, ({ many }) => ({
|
|
|
|
|
sportsSeasons: many(sportsSeasons),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const sportsSeasonsRelations = relations(sportsSeasons, ({ one, many }) => ({
|
|
|
|
|
sport: one(sports, {
|
|
|
|
|
fields: [sportsSeasons.sportId],
|
|
|
|
|
references: [sports.id],
|
|
|
|
|
}),
|
|
|
|
|
participants: many(participants),
|
|
|
|
|
seasonTemplateSports: many(seasonTemplateSports),
|
|
|
|
|
seasonSports: many(seasonSports),
|
|
|
|
|
participantResults: many(participantResults),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const participantsRelations = relations(participants, ({ one, many }) => ({
|
|
|
|
|
sportsSeason: one(sportsSeasons, {
|
|
|
|
|
fields: [participants.sportsSeasonId],
|
|
|
|
|
references: [sportsSeasons.id],
|
|
|
|
|
}),
|
|
|
|
|
results: many(participantResults),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const seasonTemplatesRelations = relations(seasonTemplates, ({ many }) => ({
|
|
|
|
|
seasonTemplateSports: many(seasonTemplateSports),
|
|
|
|
|
seasons: many(seasons),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const seasonTemplateSportsRelations = relations(seasonTemplateSports, ({ one }) => ({
|
|
|
|
|
template: one(seasonTemplates, {
|
|
|
|
|
fields: [seasonTemplateSports.templateId],
|
|
|
|
|
references: [seasonTemplates.id],
|
|
|
|
|
}),
|
|
|
|
|
sportsSeason: one(sportsSeasons, {
|
|
|
|
|
fields: [seasonTemplateSports.sportsSeasonId],
|
|
|
|
|
references: [sportsSeasons.id],
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const seasonsRelations = relations(seasons, ({ one, many }) => ({
|
|
|
|
|
league: one(leagues, {
|
|
|
|
|
fields: [seasons.leagueId],
|
|
|
|
|
references: [leagues.id],
|
|
|
|
|
}),
|
|
|
|
|
template: one(seasonTemplates, {
|
|
|
|
|
fields: [seasons.templateId],
|
|
|
|
|
references: [seasonTemplates.id],
|
|
|
|
|
}),
|
|
|
|
|
teams: many(teams),
|
|
|
|
|
seasonSports: many(seasonSports),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const seasonSportsRelations = relations(seasonSports, ({ one }) => ({
|
|
|
|
|
season: one(seasons, {
|
|
|
|
|
fields: [seasonSports.seasonId],
|
|
|
|
|
references: [seasons.id],
|
|
|
|
|
}),
|
|
|
|
|
sportsSeason: one(sportsSeasons, {
|
|
|
|
|
fields: [seasonSports.sportsSeasonId],
|
|
|
|
|
references: [sportsSeasons.id],
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
export const participantResultsRelations = relations(participantResults, ({ one }) => ({
|
|
|
|
|
participant: one(participants, {
|
|
|
|
|
fields: [participantResults.participantId],
|
|
|
|
|
references: [participants.id],
|
|
|
|
|
}),
|
|
|
|
|
sportsSeason: one(sportsSeasons, {
|
|
|
|
|
fields: [participantResults.sportsSeasonId],
|
|
|
|
|
references: [sportsSeasons.id],
|
|
|
|
|
}),
|
|
|
|
|
}));
|