import { getRepository } from '@/lib/db/client'; import { SessionClaims } from '@/lib/feature/user/clerk.model'; import { UserEntity } from '@/lib/feature/user/user.entity'; import { CreateUserModel, UpdateUserModel, UserModel, } from '@/lib/feature/user/user.model'; export const userEntityToModel = (userEntity: UserEntity): UserModel => { return { id: userEntity.id, name: userEntity.name, email: userEntity.email, role: userEntity.role, externalId: userEntity.externalId, }; }; /** * Retrieves a user by their email address. * @param email - The email address of the user to retrieve. * @returns {Promise} The user model if found, otherwise null. */ export const getUserByEmail = async ( email: string ): Promise => { const userRepository = await getRepository(UserEntity); const userEntity = await userRepository.findOneBy({ email }); if (!userEntity) { return null; } return userEntityToModel(userEntity); }; /** * Saves a new user to the database. * @param user - The user data to save. * @returns {Promise} The saved user model. * @throws {Error} If a user with the same email already exists. */ export const saveUser = async (user: CreateUserModel): Promise => { const userRepository = await getRepository(UserEntity); if (!!(await userRepository.findOneBy({ email: user.email }))) { throw new Error(`User with email ${user.email} already exists`); } const newUser = userRepository.create(user); return userEntityToModel(await userRepository.save(newUser)); }; /** * Updates an existing user in the database. * @param userId - The ID of the user to update. * @param user - The new user data. * @returns {Promise} The updated user model. * @throws {Error} If the user with the given ID does not exist. */ export const updateUser = async ( userId: string, user: UpdateUserModel ): Promise => { const userRepository = await getRepository(UserEntity); const existingUser = await userRepository.findOneBy({ id: userId }); if (!existingUser) { throw new Error(`User with ID ${userId} not found`); } if (!!user.email) existingUser.email = user.email; if (!!user.name) existingUser.name = user.name; if (!!user.role) existingUser.role = user.role; return userEntityToModel(await userRepository.save(existingUser)); }; /** * Synchronizes a user with the database. * If the user already exists, it skips saving and returns the existing user. * If the user does not exist, it creates a new user record. * @returns {Promise} The synchronized user model. * @throws {Error} If the user email is not provided or if there is an issue * saving the user. * @param sessionClaims Session Claims from the Auth Provider */ export const syncUser = async ( sessionClaims: SessionClaims ): Promise => { const { full_name, email } = sessionClaims.user; const role = sessionClaims.user.public_metadata.role; const existingUser = await getUserByEmail(email); if (!existingUser) { return await saveUser({ name: full_name, email: email, role: role, }); } return await updateUser(existingUser.id, { name: full_name, email: existingUser.email, role: role, }); };