feat: refactor article and user service functions to use TypedResult for enhanced error handling

This commit is contained in:
2026-04-11 02:01:12 -03:00
parent af17b6dc5a
commit 3ea1112369
4 changed files with 274 additions and 282 deletions

View File

@@ -18,80 +18,42 @@ export const userEntityToModel = (userEntity: UserEntity): UserModel => {
};
};
const _getUserByEmail = async (email: string): Promise<UserModel | null> => {
const userRepository = await getRepository(UserEntity);
const userEntity = await userRepository.findOneBy({ email });
if (!userEntity) {
return null;
}
return userEntityToModel(userEntity);
};
const _saveUser = async (user: CreateUserModel): Promise<UserModel> => {
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));
};
const _updateUser = async (
userId: string,
user: UpdateUserModel
): Promise<UserModel> => {
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));
};
const _syncUser = async (sessionClaims: SessionClaims): Promise<UserModel> => {
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,
});
};
/**
* Retrieves a user by their email address.
* @param email - The email address of the user to retrieve.
* @returns {Promise<TypedResult<UserModel | null>>} The user model if found, otherwise null.
*/
export const getUserByEmail = wrap(_getUserByEmail);
export const getUserByEmail = wrap(
async (email: string): Promise<UserModel | null> => {
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<TypedResult<UserModel>>} The saved user model.
*/
export const saveUser = wrap(_saveUser);
export const saveUser = wrap(
async (user: CreateUserModel): Promise<UserModel> => {
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.
@@ -99,7 +61,22 @@ export const saveUser = wrap(_saveUser);
* @param user - The new user data.
* @returns {Promise<TypedResult<UserModel>>} The updated user model.
*/
export const updateUser = wrap(_updateUser);
export const updateUser = wrap(
async (userId: string, user: UpdateUserModel): Promise<UserModel> => {
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.
@@ -107,7 +84,38 @@ export const updateUser = wrap(_updateUser);
* @param sessionClaims Session Claims from the Auth Provider
* @returns {Promise<TypedResult<UserModel>>} The synchronized user model.
*/
export const syncUser = wrap(_syncUser);
export const syncUser = wrap(
async (sessionClaims: SessionClaims): Promise<UserModel> => {
const { full_name, email } = sessionClaims.user;
const role = sessionClaims.user.public_metadata.role;
const existingUserResult = await getUserByEmail(email);
if (!existingUserResult.ok || !existingUserResult.value) {
const saveResult = await saveUser({
name: full_name,
email: email,
role: role,
});
if (!saveResult.ok) {
throw new Error(`User with email ${email} already exists`);
}
return saveResult.value;
}
const existingUser = existingUserResult.value;
const updateResult = await updateUser(existingUser.id, {
name: full_name,
email: existingUser.email,
role: role,
});
if (!updateResult.ok) {
throw new Error(
`Failed to update user with email ${email}: ${updateResult.error}`
);
}
return updateResult.value;
}
);
// Explicit re-export for TypeScript consumers who need the result type
export type { TypedResult };