Merge branch 'crud' into 'main'
Crud See merge request mobicoop/lab/v3/services/user!1
This commit is contained in:
		
						commit
						ff3ac73ecb
					
				| 
						 | 
				
			
			@ -1,10 +0,0 @@
 | 
			
		|||
-- CreateTable
 | 
			
		||||
CREATE TABLE "user" (
 | 
			
		||||
    "uuid" UUID NOT NULL,
 | 
			
		||||
    "firstName" TEXT NOT NULL,
 | 
			
		||||
    "lastName" TEXT NOT NULL,
 | 
			
		||||
    "email" TEXT NOT NULL
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "user_uuid_key" ON "user"("uuid");
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
-- CreateTable
 | 
			
		||||
CREATE TABLE "user" (
 | 
			
		||||
    "uuid" UUID NOT NULL,
 | 
			
		||||
    "firstName" TEXT NOT NULL,
 | 
			
		||||
    "lastName" TEXT NOT NULL,
 | 
			
		||||
    "email" TEXT NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "user_pkey" PRIMARY KEY ("uuid")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
 | 
			
		||||
| 
						 | 
				
			
			@ -11,10 +11,12 @@ datasource db {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
model User {
 | 
			
		||||
  uuid      String @unique @default(uuid()) @db.Uuid
 | 
			
		||||
  uuid      String   @id @default(uuid()) @db.Uuid
 | 
			
		||||
  firstName String
 | 
			
		||||
  lastName  String
 | 
			
		||||
  email     String
 | 
			
		||||
  email     String   @unique
 | 
			
		||||
  createdAt DateTime @default(now())
 | 
			
		||||
  updatedAt DateTime @updatedAt
 | 
			
		||||
 | 
			
		||||
  @@map("user")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,15 @@
 | 
			
		|||
import { classes } from '@automapper/classes';
 | 
			
		||||
import { AutomapperModule } from '@automapper/nestjs';
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { ConfigModule } from '@nestjs/config';
 | 
			
		||||
import { UsersModule } from './modules/users/users.module';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [ConfigModule.forRoot({ isGlobal: true }), UsersModule],
 | 
			
		||||
  imports: [
 | 
			
		||||
    ConfigModule.forRoot({ isGlobal: true }),
 | 
			
		||||
    AutomapperModule.forRoot({ strategyInitializer: classes() }),
 | 
			
		||||
    UsersModule,
 | 
			
		||||
  ],
 | 
			
		||||
  controllers: [],
 | 
			
		||||
  providers: [],
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,6 @@ export class DatabaseException implements Error {
 | 
			
		|||
  ) {
 | 
			
		||||
    this.name = 'DatabaseException';
 | 
			
		||||
    this.message = message ?? 'An error occured with the database.';
 | 
			
		||||
 | 
			
		||||
    if (this.message.includes('Unique constraint failed')) {
 | 
			
		||||
      this.message = 'Already exists.';
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@ package user;
 | 
			
		|||
service UsersService {
 | 
			
		||||
  rpc FindOneByUuid(UserByUuid) returns (User);
 | 
			
		||||
  rpc FindAll(UserFilter) returns (Users);
 | 
			
		||||
  rpc Create(CreateUser) returns (User);
 | 
			
		||||
  rpc Create(User) returns (User);
 | 
			
		||||
  rpc Update(User) returns (User);
 | 
			
		||||
  rpc Delete(UserByUuid) returns (Empty);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message UserByUuid {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,15 +21,10 @@ message User {
 | 
			
		|||
  string email = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message CreateUser {
 | 
			
		||||
  string uuid = 1;
 | 
			
		||||
  string firstName = 2;
 | 
			
		||||
  string lastName = 3;
 | 
			
		||||
  string email = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message UserFilter {}
 | 
			
		||||
 | 
			
		||||
message Users {
 | 
			
		||||
  repeated User users = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Empty {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,25 +1,97 @@
 | 
			
		|||
import { Mapper } from '@automapper/core';
 | 
			
		||||
import { InjectMapper } from '@automapper/nestjs';
 | 
			
		||||
import { Controller } from '@nestjs/common';
 | 
			
		||||
import { QueryBus } from '@nestjs/cqrs';
 | 
			
		||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
 | 
			
		||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
 | 
			
		||||
import { FindUserByUuidRequest } from '../../domain/dto/findUserByUuidRequest';
 | 
			
		||||
import { DatabaseException } from 'src/modules/database/src/exceptions/DatabaseException';
 | 
			
		||||
import { CreateUserCommand } from '../../commands/create-user.command';
 | 
			
		||||
import { DeleteUserCommand } from '../../commands/delete-user.command';
 | 
			
		||||
import { UpdateUserCommand } from '../../commands/update-user.command';
 | 
			
		||||
import { CreateUserRequest } from '../../domain/dto/create-user.request';
 | 
			
		||||
import { FindUserByUuidRequest } from '../../domain/dto/find-user-by-uuid.request';
 | 
			
		||||
import { UpdateUserRequest } from '../../domain/dto/update-user.request';
 | 
			
		||||
import { User } from '../../domain/entities/user';
 | 
			
		||||
import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query';
 | 
			
		||||
import { UserPresenter } from './user.presenter';
 | 
			
		||||
 | 
			
		||||
@Controller()
 | 
			
		||||
export class UsersController {
 | 
			
		||||
  constructor(private readonly _queryBus: QueryBus) {}
 | 
			
		||||
  constructor(
 | 
			
		||||
    private readonly _commandBus: CommandBus,
 | 
			
		||||
    private readonly _queryBus: QueryBus,
 | 
			
		||||
    @InjectMapper() private readonly _mapper: Mapper,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  @GrpcMethod('UsersService', 'FindOneByUuid')
 | 
			
		||||
  async findOneByUuid(data: FindUserByUuidRequest): Promise<User> {
 | 
			
		||||
  async findOneByUuid(data: FindUserByUuidRequest): Promise<UserPresenter> {
 | 
			
		||||
    const user = await this._queryBus.execute(
 | 
			
		||||
      new FindUserByUuidQuery(data.uuid),
 | 
			
		||||
    );
 | 
			
		||||
    if (user) {
 | 
			
		||||
      return user;
 | 
			
		||||
      return this._mapper.map(user, User, UserPresenter);
 | 
			
		||||
    }
 | 
			
		||||
    throw new RpcException({
 | 
			
		||||
      code: 5,
 | 
			
		||||
      message: 'User not found',
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GrpcMethod('UsersService', 'Create')
 | 
			
		||||
  async createUser(data: CreateUserRequest): Promise<UserPresenter> {
 | 
			
		||||
    try {
 | 
			
		||||
      const user = await this._commandBus.execute(new CreateUserCommand(data));
 | 
			
		||||
      return this._mapper.map(user, User, UserPresenter);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      if (e instanceof DatabaseException) {
 | 
			
		||||
        if (e.message.includes('Already exists')) {
 | 
			
		||||
          throw new RpcException({
 | 
			
		||||
            code: 6,
 | 
			
		||||
            message: 'User already exists',
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      throw new RpcException({});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GrpcMethod('UsersService', 'Update')
 | 
			
		||||
  async updateUser(data: UpdateUserRequest): Promise<UserPresenter> {
 | 
			
		||||
    try {
 | 
			
		||||
      const user = await this._commandBus.execute(new UpdateUserCommand(data));
 | 
			
		||||
 | 
			
		||||
      return this._mapper.map(user, User, UserPresenter);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      if (e instanceof DatabaseException) {
 | 
			
		||||
        if (e.message.includes('not found')) {
 | 
			
		||||
          throw new RpcException({
 | 
			
		||||
            code: 5,
 | 
			
		||||
            message: 'User not found',
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      throw new RpcException({});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GrpcMethod('UsersService', 'Delete')
 | 
			
		||||
  async deleteUser(data: FindUserByUuidRequest): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
      const user = await this._commandBus.execute(
 | 
			
		||||
        new DeleteUserCommand(data.uuid),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      return Promise.resolve();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      if (e instanceof DatabaseException) {
 | 
			
		||||
        if (e.message.includes('not found')) {
 | 
			
		||||
          throw new RpcException({
 | 
			
		||||
            code: 5,
 | 
			
		||||
            message: 'User not found',
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      throw new RpcException({});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
import { CreateUserRequest } from '../domain/dto/create-user.request';
 | 
			
		||||
 | 
			
		||||
export class CreateUserCommand {
 | 
			
		||||
  readonly createUserRequest: CreateUserRequest;
 | 
			
		||||
 | 
			
		||||
  constructor(request: CreateUserRequest) {
 | 
			
		||||
    this.createUserRequest = request;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
export class DeleteUserCommand {
 | 
			
		||||
  readonly uuid: string;
 | 
			
		||||
 | 
			
		||||
  constructor(uuid: string) {
 | 
			
		||||
    this.uuid = uuid;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
import { UpdateUserRequest } from '../domain/dto/update-user.request';
 | 
			
		||||
 | 
			
		||||
export class UpdateUserCommand {
 | 
			
		||||
  readonly updateUserRequest: UpdateUserRequest;
 | 
			
		||||
 | 
			
		||||
  constructor(request: UpdateUserRequest) {
 | 
			
		||||
    this.updateUserRequest = request;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
import { AutoMap } from '@automapper/classes';
 | 
			
		||||
import { IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class CreateUserRequest {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  uuid: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  firstName: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  lastName: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  email: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
import { IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class FindUserByUuidRequest {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  uuid: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
import { IsString } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class FindUserByUuidRequest {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  uuid: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
import { AutoMap } from '@automapper/classes';
 | 
			
		||||
import { IsString } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class UpdateUserRequest {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  uuid: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  firstName?: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  lastName?: string;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @AutoMap()
 | 
			
		||||
  email?: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
import { Mapper } from '@automapper/core';
 | 
			
		||||
import { InjectMapper } from '@automapper/nestjs';
 | 
			
		||||
import { CommandHandler } from '@nestjs/cqrs';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { CreateUserCommand } from '../../commands/create-user.command';
 | 
			
		||||
import { CreateUserRequest } from '../dto/create-user.request';
 | 
			
		||||
import { User } from '../entities/user';
 | 
			
		||||
 | 
			
		||||
@CommandHandler(CreateUserCommand)
 | 
			
		||||
export class CreateUserUseCase {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private readonly _repository: UsersRepository,
 | 
			
		||||
    @InjectMapper() private readonly _mapper: Mapper,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  async execute(command: CreateUserCommand): Promise<User> {
 | 
			
		||||
    const entity = this._mapper.map(
 | 
			
		||||
      command.createUserRequest,
 | 
			
		||||
      CreateUserRequest,
 | 
			
		||||
      User,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return this._repository.create(entity);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
import { CommandHandler } from '@nestjs/cqrs';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { DeleteUserCommand } from '../../commands/delete-user.command';
 | 
			
		||||
 | 
			
		||||
@CommandHandler(DeleteUserCommand)
 | 
			
		||||
export class DeleteUserUseCase {
 | 
			
		||||
  constructor(private readonly _repository: UsersRepository) {}
 | 
			
		||||
 | 
			
		||||
  async execute(command: DeleteUserCommand): Promise<void> {
 | 
			
		||||
    return this._repository.delete(command.uuid);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
import { Mapper } from '@automapper/core';
 | 
			
		||||
import { InjectMapper } from '@automapper/nestjs';
 | 
			
		||||
import { CommandHandler } from '@nestjs/cqrs';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { UpdateUserCommand } from '../../commands/update-user.command';
 | 
			
		||||
import { UpdateUserRequest } from '../dto/update-user.request';
 | 
			
		||||
import { User } from '../entities/user';
 | 
			
		||||
 | 
			
		||||
@CommandHandler(UpdateUserCommand)
 | 
			
		||||
export class UpdateUserUseCase {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private readonly _repository: UsersRepository,
 | 
			
		||||
    @InjectMapper() private readonly _mapper: Mapper,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  async execute(command: UpdateUserCommand): Promise<User> {
 | 
			
		||||
    const entity = this._mapper.map(
 | 
			
		||||
      command.updateUserRequest,
 | 
			
		||||
      UpdateUserRequest,
 | 
			
		||||
      User,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return this._repository.update(command.updateUserRequest.uuid, entity);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,9 @@
 | 
			
		|||
import { createMap, Mapper } from '@automapper/core';
 | 
			
		||||
import { createMap, forMember, ignore, Mapper } from '@automapper/core';
 | 
			
		||||
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { UserPresenter } from '../adapters/primaries/user.presenter';
 | 
			
		||||
import { CreateUserRequest } from '../domain/dto/create-user.request';
 | 
			
		||||
import { UpdateUserRequest } from '../domain/dto/update-user.request';
 | 
			
		||||
import { User } from '../domain/entities/user';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +15,15 @@ export class UserProfile extends AutomapperProfile {
 | 
			
		|||
  override get profile() {
 | 
			
		||||
    return (mapper) => {
 | 
			
		||||
      createMap(mapper, User, UserPresenter);
 | 
			
		||||
 | 
			
		||||
      createMap(mapper, CreateUserRequest, User);
 | 
			
		||||
 | 
			
		||||
      createMap(
 | 
			
		||||
        mapper,
 | 
			
		||||
        UpdateUserRequest,
 | 
			
		||||
        User,
 | 
			
		||||
        forMember((dest) => dest.uuid, ignore()),
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
import { classes } from '@automapper/classes';
 | 
			
		||||
import { AutomapperModule } from '@automapper/nestjs';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { CreateUserCommand } from '../../commands/create-user.command';
 | 
			
		||||
import { CreateUserRequest } from '../../domain/dto/create-user.request';
 | 
			
		||||
import { User } from '../../domain/entities/user';
 | 
			
		||||
import { CreateUserUseCase } from '../../domain/usecases/create-user.usecase';
 | 
			
		||||
import { UserProfile } from '../../mappers/user.profile';
 | 
			
		||||
 | 
			
		||||
const newUserRequest: CreateUserRequest = {
 | 
			
		||||
  uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
			
		||||
  firstName: 'John',
 | 
			
		||||
  lastName: 'Doe',
 | 
			
		||||
  email: 'john.doe@email.com',
 | 
			
		||||
};
 | 
			
		||||
const newUserCommand: CreateUserCommand = new CreateUserCommand(newUserRequest);
 | 
			
		||||
 | 
			
		||||
const mockUsersRepository = {
 | 
			
		||||
  create: jest.fn().mockResolvedValue({
 | 
			
		||||
    ...newUserRequest,
 | 
			
		||||
    uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
			
		||||
  }),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('CreateUserUseCase', () => {
 | 
			
		||||
  let createUserUseCase: CreateUserUseCase;
 | 
			
		||||
 | 
			
		||||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })],
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: UsersRepository,
 | 
			
		||||
          useValue: mockUsersRepository,
 | 
			
		||||
        },
 | 
			
		||||
        CreateUserUseCase,
 | 
			
		||||
        UserProfile,
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
    createUserUseCase = module.get<CreateUserUseCase>(CreateUserUseCase);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(createUserUseCase).toBeDefined();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('execute', () => {
 | 
			
		||||
    it('should create an User and returns new entity object', async () => {
 | 
			
		||||
      const newUser: User = await createUserUseCase.execute(newUserCommand);
 | 
			
		||||
 | 
			
		||||
      expect(newUser.lastName).toBe(newUserRequest.lastName);
 | 
			
		||||
      expect(newUser.uuid).toBeDefined();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { DeleteUserCommand } from '../../commands/delete-user.command';
 | 
			
		||||
import { DeleteUserUseCase } from '../../domain/usecases/delete-user.usecase';
 | 
			
		||||
 | 
			
		||||
const usersMock = [
 | 
			
		||||
  {
 | 
			
		||||
    uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
			
		||||
    firstName: 'John',
 | 
			
		||||
    lastName: 'Doe',
 | 
			
		||||
    email: 'john.doe@email.com',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
 | 
			
		||||
    firstName: 'Jane',
 | 
			
		||||
    lastName: 'Doe',
 | 
			
		||||
    email: 'jane.doe@email.com',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
 | 
			
		||||
    firstName: 'Jimmy',
 | 
			
		||||
    lastName: 'Doe',
 | 
			
		||||
    email: 'jimmy.doe@email.com',
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const mockUsersRepository = {
 | 
			
		||||
  delete: jest.fn().mockImplementation((uuid: string) => {
 | 
			
		||||
    usersMock.forEach((user, index) => {
 | 
			
		||||
      if (user.uuid === uuid) {
 | 
			
		||||
        usersMock.splice(index, 1);
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('DeleteUserUseCase', () => {
 | 
			
		||||
  let deleteUserUseCase: DeleteUserUseCase;
 | 
			
		||||
 | 
			
		||||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: UsersRepository,
 | 
			
		||||
          useValue: mockUsersRepository,
 | 
			
		||||
        },
 | 
			
		||||
        DeleteUserUseCase,
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
    deleteUserUseCase = module.get<DeleteUserUseCase>(DeleteUserUseCase);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(deleteUserUseCase).toBeDefined();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('execute', () => {
 | 
			
		||||
    it('should delete an User', async () => {
 | 
			
		||||
      const savedUuid = usersMock[0].uuid;
 | 
			
		||||
      const deleteUserCommand = new DeleteUserCommand(savedUuid);
 | 
			
		||||
      await deleteUserUseCase.execute(deleteUserCommand);
 | 
			
		||||
 | 
			
		||||
      const deletedUser = usersMock.find((user) => user.uuid === savedUuid);
 | 
			
		||||
      expect(deletedUser).toBeUndefined();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,6 @@ describe('FindUserByUuidUseCase', () => {
 | 
			
		|||
          provide: UsersRepository,
 | 
			
		||||
          useValue: mockUserRepository,
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        FindUserByUuidUseCase,
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
import { classes } from '@automapper/classes';
 | 
			
		||||
import { AutomapperModule } from '@automapper/nestjs';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
import { UsersRepository } from '../../adapters/secondaries/users.repository';
 | 
			
		||||
import { UpdateUserCommand } from '../../commands/update-user.command';
 | 
			
		||||
import { UpdateUserRequest } from '../../domain/dto/update-user.request';
 | 
			
		||||
import { User } from '../../domain/entities/user';
 | 
			
		||||
import { UpdateUserUseCase } from '../../domain/usecases/update-user.usecase';
 | 
			
		||||
import { UserProfile } from '../../mappers/user.profile';
 | 
			
		||||
 | 
			
		||||
const originalUser: User = new User();
 | 
			
		||||
originalUser.uuid = 'bb281075-1b98-4456-89d6-c643d3044a91';
 | 
			
		||||
originalUser.lastName = 'Doe';
 | 
			
		||||
 | 
			
		||||
const updateUserRequest: UpdateUserRequest = {
 | 
			
		||||
  uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
			
		||||
  lastName: 'Dane',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const updateUserCommand: UpdateUserCommand = new UpdateUserCommand(
 | 
			
		||||
  updateUserRequest,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const mockUsersRepository = {
 | 
			
		||||
  update: jest.fn().mockImplementation((uuid: string, params: any) => {
 | 
			
		||||
    originalUser.lastName = params.lastName;
 | 
			
		||||
 | 
			
		||||
    return Promise.resolve(originalUser);
 | 
			
		||||
  }),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('UpdateUserUseCase', () => {
 | 
			
		||||
  let updateUserUseCase: UpdateUserUseCase;
 | 
			
		||||
 | 
			
		||||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })],
 | 
			
		||||
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: UsersRepository,
 | 
			
		||||
          useValue: mockUsersRepository,
 | 
			
		||||
        },
 | 
			
		||||
        UpdateUserUseCase,
 | 
			
		||||
        UserProfile,
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
    updateUserUseCase = module.get<UpdateUserUseCase>(UpdateUserUseCase);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(updateUserUseCase).toBeDefined();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('execute', () => {
 | 
			
		||||
    it('should update an User', async () => {
 | 
			
		||||
      const updatedUser: User = await updateUserUseCase.execute(
 | 
			
		||||
        updateUserCommand,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      expect(updatedUser.lastName).toBe(updateUserRequest.lastName);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -3,12 +3,23 @@ import { CqrsModule } from '@nestjs/cqrs';
 | 
			
		|||
import { DatabaseModule } from '../database/database.module';
 | 
			
		||||
import { UsersController } from './adapters/primaries/users.controller';
 | 
			
		||||
import { UsersRepository } from './adapters/secondaries/users.repository';
 | 
			
		||||
import { CreateUserUseCase } from './domain/usecases/create-user.usecase';
 | 
			
		||||
import { DeleteUserUseCase } from './domain/usecases/delete-user.usecase';
 | 
			
		||||
import { FindUserByUuidUseCase } from './domain/usecases/find-user-by-uuid.usecase';
 | 
			
		||||
import { UpdateUserUseCase } from './domain/usecases/update-user.usecase';
 | 
			
		||||
import { UserProfile } from './mappers/user.profile';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [DatabaseModule, CqrsModule],
 | 
			
		||||
  controllers: [UsersController],
 | 
			
		||||
  providers: [UsersRepository, FindUserByUuidUseCase],
 | 
			
		||||
  providers: [
 | 
			
		||||
    UserProfile,
 | 
			
		||||
    UsersRepository,
 | 
			
		||||
    FindUserByUuidUseCase,
 | 
			
		||||
    CreateUserUseCase,
 | 
			
		||||
    UpdateUserUseCase,
 | 
			
		||||
    DeleteUserUseCase,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [],
 | 
			
		||||
})
 | 
			
		||||
export class UsersModule {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue