import { eq } from "drizzle-orm"; import { database } from "~/database/context"; import * as schema from "~/database/schema"; export type User = typeof schema.users.$inferSelect; export type NewUser = typeof schema.users.$inferInsert; export async function createUser(data: NewUser): Promise { const db = database(); const [user] = await db.insert(schema.users).values(data).returning(); return user; } export async function findUserById(id: string): Promise { const db = database(); return await db.query.users.findFirst({ where: eq(schema.users.id, id), }); } export async function findUserByClerkId( clerkId: string ): Promise { const db = database(); return await db.query.users.findFirst({ where: eq(schema.users.clerkId, clerkId), }); } export async function updateUser( id: string, data: Partial ): Promise { const db = database(); const [user] = await db .update(schema.users) .set({ ...data, updatedAt: new Date() }) .where(eq(schema.users.id, id)) .returning(); return user; } export async function updateUserByClerkId( clerkId: string, data: Partial ): Promise { const db = database(); const [user] = await db .update(schema.users) .set({ ...data, updatedAt: new Date() }) .where(eq(schema.users.clerkId, clerkId)) .returning(); return user; } export async function findOrCreateUser(clerkUser: { id: string; emailAddresses?: Array<{ emailAddress: string }>; username?: string | null; firstName?: string | null; lastName?: string | null; imageUrl?: string; }): Promise { // Try to find existing user const existingUser = await findUserByClerkId(clerkUser.id); const email = clerkUser.emailAddresses?.[0]?.emailAddress; if (!email) { throw new Error("User must have an email address"); } // Generate display name: firstName lastName, or email username let displayName = ""; if (clerkUser.firstName || clerkUser.lastName) { displayName = [clerkUser.firstName, clerkUser.lastName] .filter(Boolean) .join(" ") .trim(); } else { // Use email username as fallback displayName = email.split("@")[0]; } if (existingUser) { // Update user info in case it changed in Clerk return await updateUserByClerkId(clerkUser.id, { email, username: clerkUser.username || undefined, displayName, firstName: clerkUser.firstName || undefined, lastName: clerkUser.lastName || undefined, imageUrl: clerkUser.imageUrl, }); } // Create new user return await createUser({ clerkId: clerkUser.id, email, username: clerkUser.username || undefined, displayName, firstName: clerkUser.firstName || undefined, lastName: clerkUser.lastName || undefined, imageUrl: clerkUser.imageUrl, }); } export async function deleteUser(id: string): Promise { const db = database(); await db.delete(schema.users).where(eq(schema.users.id, id)); } export async function findAdmins(): Promise { const db = database(); return await db.query.users.findMany({ where: eq(schema.users.isAdmin, true), orderBy: (users, { asc }) => [asc(users.displayName)], }); } export async function isUserAdmin(userId: string): Promise { const user = await findUserById(userId); return user?.isAdmin ?? false; } export async function isUserAdminByClerkId(clerkId: string): Promise { const user = await findUserByClerkId(clerkId); return user?.isAdmin ?? false; } export async function setUserAdmin(userId: string, isAdmin: boolean): Promise { return await updateUser(userId, { isAdmin }); } export async function findAllUsers(): Promise { const db = database(); return await db.query.users.findMany({ orderBy: (users, { asc }) => [asc(users.displayName)], }); }