109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
|
|
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<User> {
|
||
|
|
const db = database();
|
||
|
|
const [user] = await db.insert(schema.users).values(data).returning();
|
||
|
|
return user;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function findUserById(id: string): Promise<User | undefined> {
|
||
|
|
const db = database();
|
||
|
|
return await db.query.users.findFirst({
|
||
|
|
where: eq(schema.users.id, id),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function findUserByClerkId(
|
||
|
|
clerkId: string
|
||
|
|
): Promise<User | undefined> {
|
||
|
|
const db = database();
|
||
|
|
return await db.query.users.findFirst({
|
||
|
|
where: eq(schema.users.clerkId, clerkId),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function updateUser(
|
||
|
|
id: string,
|
||
|
|
data: Partial<NewUser>
|
||
|
|
): Promise<User> {
|
||
|
|
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<NewUser>
|
||
|
|
): Promise<User> {
|
||
|
|
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 }>;
|
||
|
|
firstName?: string | null;
|
||
|
|
lastName?: string | null;
|
||
|
|
imageUrl?: string;
|
||
|
|
}): Promise<User> {
|
||
|
|
// 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,
|
||
|
|
displayName,
|
||
|
|
firstName: clerkUser.firstName || undefined,
|
||
|
|
lastName: clerkUser.lastName || undefined,
|
||
|
|
imageUrl: clerkUser.imageUrl,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create new user
|
||
|
|
return await createUser({
|
||
|
|
clerkId: clerkUser.id,
|
||
|
|
email,
|
||
|
|
displayName,
|
||
|
|
firstName: clerkUser.firstName || undefined,
|
||
|
|
lastName: clerkUser.lastName || undefined,
|
||
|
|
imageUrl: clerkUser.imageUrl,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function deleteUser(id: string): Promise<void> {
|
||
|
|
const db = database();
|
||
|
|
await db.delete(schema.users).where(eq(schema.users.id, id));
|
||
|
|
}
|