From 2d2c7a2a5b7bc078d9e1e023d64db991e5ea1c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Guzm=C3=A1n?= Date: Mon, 16 Sep 2024 19:45:39 -0300 Subject: [PATCH] feat: update user profile update logic to use upsert operation --- src/authn/index.ts | 4 +- src/datasources/queries/users.ts | 76 ++++++++++++++------------------ 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/authn/index.ts b/src/authn/index.ts index a1a326fe..709d6e48 100644 --- a/src/authn/index.ts +++ b/src/authn/index.ts @@ -5,7 +5,7 @@ import { ORM_TYPE } from "~/datasources/db"; import { insertUsersSchema, USER } from "~/datasources/db/schema"; import { findUserByID, - updateUserProfileInfo, + upsertUserProfileInfo, } from "~/datasources/queries/users"; import { getUsername } from "~/datasources/queries/utils/createUsername"; import { unauthorizedError } from "~/errors"; @@ -141,7 +141,7 @@ export const upsertUserFromRequest = async ({ logger.info(`Updating profile Info for user ID: ${sub}`); - return updateUserProfileInfo(DB, profileInfo.data, logger); + return upsertUserProfileInfo(DB, profileInfo.data, logger); }; export const logPossibleUserIdFromJWT = (request: Request, logger: Logger) => { diff --git a/src/datasources/queries/users.ts b/src/datasources/queries/users.ts index 18dbc6ad..72033a2a 100644 --- a/src/datasources/queries/users.ts +++ b/src/datasources/queries/users.ts @@ -1,4 +1,3 @@ -import { eq } from "drizzle-orm"; import { z } from "zod"; import { ORM_TYPE } from "~/datasources/db"; @@ -20,64 +19,55 @@ export const findUserByID = async (db: ORM_TYPE, id: string) => { return result ? selectUsersSchema.parse(result) : null; }; -export const updateUserProfileInfo = async ( +export const upsertUserProfileInfo = async ( db: ORM_TYPE, parsedProfileInfo: z.infer, logger: Logger, ) => { - const result = await db.query.usersSchema.findFirst({ - where: (u, { eq }) => eq(u.email, parsedProfileInfo.email.toLowerCase()), - }); + logger.info( + `Upserting user profile info for ${parsedProfileInfo.email} (externalId: ${ + parsedProfileInfo.externalId || "N/A" + })`, + ); + + const { email, externalId, name, imageUrl, isEmailVerified, publicMetadata } = + parsedProfileInfo; + const lowercaseEmail = email.trim().toLowerCase(); + + const upsertData: z.infer = { + externalId, + name, + imageUrl, + isEmailVerified, + publicMetadata: publicMetadata ?? {}, + status: UserStatusEnum.active, + }; - if (!result) { - logger.info("User not found — creating new user"); - // we create the user - const createdUsers = await db + try { + const result = await db .insert(usersSchema) .values({ - externalId: parsedProfileInfo.externalId, - email: parsedProfileInfo.email.trim().toLowerCase(), + ...upsertData, + email: lowercaseEmail, username: parsedProfileInfo.username ?? getUsername(), - name: parsedProfileInfo.name, - imageUrl: parsedProfileInfo.imageUrl, - isEmailVerified: parsedProfileInfo.isEmailVerified, - publicMetadata: parsedProfileInfo.publicMetadata ?? {}, - status: UserStatusEnum.active, + }) + .onConflictDoUpdate({ + target: usersSchema.email, + set: allowedUserUpdateForAuth.parse(upsertData), }) .returning(); - const createdUser = createdUsers?.[0]; - - if (!createdUser) { - logger.error("Could not create user"); - throw new Error("Could not create user"); - } - return selectUsersSchema.parse(createdUser); - } else { - logger.info("User found — updating user"); - // we update the user - const updateData = allowedUserUpdateForAuth.parse({ - externalId: parsedProfileInfo.externalId, - name: parsedProfileInfo.name, - imageUrl: parsedProfileInfo.imageUrl, - isEmailVerified: parsedProfileInfo.isEmailVerified, - publicMetadata: parsedProfileInfo.publicMetadata ?? {}, - status: UserStatusEnum.active, - }); - const updatedUsers = await db - .update(usersSchema) - .set(updateData) - .where(eq(usersSchema.email, parsedProfileInfo.email)) - .returning(); - const updatedUser = updatedUsers?.[0]; + const updatedUser = result[0]; if (!updatedUser) { - logger.error("Could not update user"); - throw new Error("Could not update user"); + throw new Error("User operation failed"); } - logger.info("User updated"); + logger.info(result.length > 1 ? "User updated" : "New user created"); return selectUsersSchema.parse(updatedUser); + } catch (error) { + logger.error("Error in user operation", { error }); + throw new Error("User operation failed"); } };