This commit is contained in:
David Arranz 2024-05-20 10:59:15 +02:00
parent e350e65f37
commit c040a247e7
5 changed files with 76 additions and 48 deletions

View File

@ -57,7 +57,7 @@ export class Password extends StringValueObject {
return Result.ok(new Password(validationResult.object));
}
public static async createFromPlainTextPassword(
public static createFromPlainTextPassword(
value: UndefinedOr<string>,
options: IPasswordOptions = {},
) {
@ -79,7 +79,7 @@ export class Password extends StringValueObject {
}
return Result.ok(
new Password(await Password.hashPassword(validationResult.object)),
new Password(Password.hashPassword(validationResult.object)),
);
}

View File

@ -126,14 +126,14 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
): Promise<void> {
const _model = this.adapter.getModel(modelName);
if (await this._exists(modelName, "id", id.toString())) {
if (await this._exists(modelName, "id", id.toPrimitive())) {
await _model.update(
{
...data,
id: undefined,
},
{
where: { id: id.toString() },
where: { id: id.toPrimitive() },
transaction: this.transaction,
...params,
},
@ -142,7 +142,7 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
await _model.create(
{
...data,
id: id.toString(),
id: id.toPrimitive(),
},
{
include: [{ all: true }],
@ -163,7 +163,7 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
await model.destroy({
where: {
id: id.toString(),
id: id.toPrimitive(),
},
transaction: this.transaction,
force,
@ -192,7 +192,7 @@ export abstract class SequelizeRepository<T> implements IRepository<T> {
modelName: string,
ids: UniqueID[] | string[]
): Promise<boolean> {
const _ids = ids.map((id: UniqueID | string) => id.toString());
const _ids = ids.map((id: UniqueID | string) => id.toPrimitive());
const destroyedRows: Promise<number> = await this.adapter.models[
modelName

View File

@ -3,7 +3,7 @@ import {
IUseCaseError,
UseCaseError,
} from "@/contexts/common/application";
import { IRepositoryManager } from "@/contexts/common/domain";
import { IRepositoryManager, Password } from "@/contexts/common/domain";
import { IInfrastructureError } from "@/contexts/common/infrastructure";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import {
@ -12,14 +12,13 @@ import {
ICreateUser_Request_DTO,
IDomainError,
Name,
Password,
Result,
UniqueID,
ensureEmailIsValid,
ensureIdIsValid,
ensureNameIsValid,
} from "@shared/contexts";
import { IUserRepository, User } from "../domain";
import { existsUserByEmail, existsUserByID } from "./userServices";
export type CreateUserResponseOrError =
| Result<never, IUseCaseError> // Misc errors (value objects)
@ -41,15 +40,12 @@ export class CreateUserUseCase
}
async execute(request: ICreateUser_Request_DTO) {
const { id, email } = request;
const userRepository = this._getUserRepository();
const { id, name, email } = request;
// Validaciones de datos
const userIdOrError = ensureIdIsValid(id);
if (userIdOrError.isFailure) {
const message = userIdOrError.error.message; //`User ID ${userDTO.id} is not valid`;
const idOrError = ensureIdIsValid(id);
if (idOrError.isFailure) {
const message = idOrError.error.message; //`User ID ${userDTO.id} is not valid`;
return Result.fail(
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [
{ path: "id" },
@ -57,13 +53,32 @@ export class CreateUserUseCase
);
}
const idExists = await existsUserByID(
userIdOrError.object,
this._adapter,
userRepository,
);
const nameOrError = ensureNameIsValid(name);
if (nameOrError.isFailure) {
const message = nameOrError.error.message; //`User ID ${userDTO.id} is not valid`;
return Result.fail(
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [
{ path: "name" },
]),
);
}
const emailOrError = ensureEmailIsValid(email);
if (emailOrError.isFailure) {
const message = emailOrError.error.message;
return Result.fail(
UseCaseError.create(UseCaseError.INVALID_INPUT_DATA, message, [
{ path: "email" },
]),
);
}
// Comprobar que no existe un usuario previo con esos datos
const userRepository = this._getUserRepository();
const idExists = await userRepository().existsUserWithId(idOrError.object);
if (idExists) {
const message = `Another user with ID ${id} exists`;
const message = `Another user with same ID exists`;
return Result.fail(
UseCaseError.create(UseCaseError.RESOURCE_ALREADY_EXITS, message, {
path: "id",
@ -71,38 +86,33 @@ export class CreateUserUseCase
);
}
const emailOrError = ensureEmailIsValid(email);
if (emailOrError.isFailure) {
const nameExists = await userRepository().existsUserWithName(
nameOrError.object,
);
if (nameExists) {
const message = `Another user with same name exists`;
return Result.fail(
UseCaseError.create(
UseCaseError.INVALID_INPUT_DATA,
"Email or password is not valid",
emailOrError.error,
),
UseCaseError.create(UseCaseError.RESOURCE_ALREADY_EXITS, message, {
path: "name",
}),
);
}
const emailExists = await existsUserByEmail(
const emailExists = await userRepository().existsUserWithEmail(
emailOrError.object,
this._adapter,
userRepository,
);
if (emailExists) {
const message = `Another user with same email exists`;
return Result.fail(
UseCaseError.create(
UseCaseError.RESOURCE_ALREADY_EXITS,
`Another user with email ${email} exists`,
{ path: "email" },
),
UseCaseError.create(UseCaseError.RESOURCE_ALREADY_EXITS, message, {
path: "email",
}),
);
}
// Crear user
const userOrError = this._tryCreateUserInstance(
request,
userIdOrError.object,
);
const userOrError = this._tryCreateUserInstance(request, idOrError.object);
if (userOrError.isFailure) {
const { error: domainError } = userOrError;
@ -180,7 +190,9 @@ export class CreateUserUseCase
return Result.fail(emailOrError.error);
}
const passwordOrError = Password.createFromPlainText(userDTO.password);
const passwordOrError = Password.createFromPlainTextPassword(
userDTO.password,
);
if (passwordOrError.isFailure) {
return Result.fail(passwordOrError.error);
}

View File

@ -1,5 +1,11 @@
import { IRepository } from "@/contexts/common/domain";
import { Email, ICollection, IQueryCriteria, UniqueID } from "@shared/contexts";
import {
Email,
ICollection,
IQueryCriteria,
Name,
UniqueID,
} from "@shared/contexts";
import { User } from "../entities";
export interface IUserRepository extends IRepository<any> {
@ -13,5 +19,6 @@ export interface IUserRepository extends IRepository<any> {
removeById(id: UniqueID): Promise<void>;
existsUserWithId(id: UniqueID): Promise<boolean>;
existsUserWithName(name: Name): Promise<boolean>;
existsUserWithEmail(email: Email): Promise<boolean>;
}

View File

@ -2,7 +2,13 @@ import {
ISequelizeAdapter,
SequelizeRepository,
} from "@/contexts/common/infrastructure/sequelize";
import { Email, ICollection, IQueryCriteria, UniqueID } from "@shared/contexts";
import {
Email,
ICollection,
IQueryCriteria,
Name,
UniqueID,
} from "@shared/contexts";
import { Transaction } from "sequelize";
import { User } from "../domain";
import { IUserRepository } from "../domain/repository";
@ -40,7 +46,6 @@ export class UserRepository
// borrando y luego creando
await this.removeById(user.id, true);
await this._save("User_Model", user.id, userData, {});
}
@ -87,11 +92,15 @@ export class UserRepository
}
public async existsUserWithId(id: UniqueID): Promise<boolean> {
return this._exists("User_Model", "id", id.toString());
return this._exists("User_Model", "id", id.toPrimitive());
}
public async existsUserWithName(name: Name): Promise<boolean> {
return this._exists("User_Model", "name", name.toPrimitive());
}
public async existsUserWithEmail(email: Email): Promise<boolean> {
return this._exists("User_Model", "email", email.toString());
return this._exists("User_Model", "email", email.toPrimitive());
}
}