Adds new user, playlist, and favorites management API endpoints and React components. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 50814a1e-92e4-4968-856f-7bc7eedf5e8f Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/50814a1e-92e4-4968-856f-7bc7eedf5e8f/hISDNbZ
144 lines
5.1 KiB
TypeScript
144 lines
5.1 KiB
TypeScript
import { sql } from "drizzle-orm";
|
|
import { pgTable, text, varchar, integer, timestamp, boolean, primaryKey, uuid } from "drizzle-orm/pg-core";
|
|
import { relations } from "drizzle-orm";
|
|
import { createInsertSchema } from "drizzle-zod";
|
|
import { z } from "zod";
|
|
|
|
export const videos = pgTable("videos", {
|
|
id: varchar("id").primaryKey(),
|
|
title: text("title").notNull(),
|
|
description: text("description"),
|
|
thumbnailUrl: text("thumbnail_url").notNull(),
|
|
videoUrl: text("video_url").notNull(),
|
|
duration: integer("duration").notNull(), // in seconds
|
|
views: integer("views").notNull().default(0),
|
|
category: text("category"),
|
|
createdAt: timestamp("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
});
|
|
|
|
export const insertVideoSchema = createInsertSchema(videos).omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export type InsertVideo = z.infer<typeof insertVideoSchema>;
|
|
export type Video = typeof videos.$inferSelect;
|
|
|
|
// Users table for authentication and user management
|
|
export const users = pgTable("users", {
|
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
|
username: varchar("username", { length: 50 }).notNull().unique(),
|
|
email: varchar("email", { length: 255 }).notNull().unique(),
|
|
passwordHash: varchar("password_hash", { length: 255 }).notNull(),
|
|
firstName: varchar("first_name", { length: 100 }),
|
|
lastName: varchar("last_name", { length: 100 }),
|
|
avatar: text("avatar"),
|
|
isActive: boolean("is_active").notNull().default(true),
|
|
createdAt: timestamp("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
updatedAt: timestamp("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
});
|
|
|
|
export const insertUserSchema = createInsertSchema(users).omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export type InsertUser = z.infer<typeof insertUserSchema>;
|
|
export type User = typeof users.$inferSelect;
|
|
|
|
// Playlists table
|
|
export const playlists = pgTable("playlists", {
|
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
|
userId: uuid("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
name: varchar("name", { length: 255 }).notNull(),
|
|
description: text("description"),
|
|
isPublic: boolean("is_public").notNull().default(false),
|
|
thumbnailUrl: text("thumbnail_url"),
|
|
createdAt: timestamp("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
updatedAt: timestamp("updated_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
});
|
|
|
|
export const insertPlaylistSchema = createInsertSchema(playlists).omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export type InsertPlaylist = z.infer<typeof insertPlaylistSchema>;
|
|
export type Playlist = typeof playlists.$inferSelect;
|
|
|
|
// Playlist videos junction table
|
|
export const playlistVideos = pgTable("playlist_videos", {
|
|
playlistId: uuid("playlist_id").notNull().references(() => playlists.id, { onDelete: "cascade" }),
|
|
videoId: varchar("video_id").notNull().references(() => videos.id, { onDelete: "cascade" }),
|
|
position: integer("position").notNull().default(0),
|
|
addedAt: timestamp("added_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
}, (table) => ({
|
|
pk: primaryKey({ columns: [table.playlistId, table.videoId] }),
|
|
}));
|
|
|
|
export const insertPlaylistVideoSchema = createInsertSchema(playlistVideos).omit({
|
|
addedAt: true,
|
|
});
|
|
|
|
export type InsertPlaylistVideo = z.infer<typeof insertPlaylistVideoSchema>;
|
|
export type PlaylistVideo = typeof playlistVideos.$inferSelect;
|
|
|
|
// User favorites table
|
|
export const userFavorites = pgTable("user_favorites", {
|
|
userId: uuid("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
videoId: varchar("video_id").notNull().references(() => videos.id, { onDelete: "cascade" }),
|
|
createdAt: timestamp("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
|
}, (table) => ({
|
|
pk: primaryKey({ columns: [table.userId, table.videoId] }),
|
|
}));
|
|
|
|
export const insertUserFavoriteSchema = createInsertSchema(userFavorites).omit({
|
|
createdAt: true,
|
|
});
|
|
|
|
export type InsertUserFavorite = z.infer<typeof insertUserFavoriteSchema>;
|
|
export type UserFavorite = typeof userFavorites.$inferSelect;
|
|
|
|
// Relations
|
|
export const usersRelations = relations(users, ({ many }) => ({
|
|
playlists: many(playlists),
|
|
favorites: many(userFavorites),
|
|
}));
|
|
|
|
export const playlistsRelations = relations(playlists, ({ one, many }) => ({
|
|
user: one(users, {
|
|
fields: [playlists.userId],
|
|
references: [users.id],
|
|
}),
|
|
playlistVideos: many(playlistVideos),
|
|
}));
|
|
|
|
export const videosRelations = relations(videos, ({ many }) => ({
|
|
playlistVideos: many(playlistVideos),
|
|
userFavorites: many(userFavorites),
|
|
}));
|
|
|
|
export const playlistVideosRelations = relations(playlistVideos, ({ one }) => ({
|
|
playlist: one(playlists, {
|
|
fields: [playlistVideos.playlistId],
|
|
references: [playlists.id],
|
|
}),
|
|
video: one(videos, {
|
|
fields: [playlistVideos.videoId],
|
|
references: [videos.id],
|
|
}),
|
|
}));
|
|
|
|
export const userFavoritesRelations = relations(userFavorites, ({ one }) => ({
|
|
user: one(users, {
|
|
fields: [userFavorites.userId],
|
|
references: [users.id],
|
|
}),
|
|
video: one(videos, {
|
|
fields: [userFavorites.videoId],
|
|
references: [videos.id],
|
|
}),
|
|
}));
|