diff --git a/src/modules/users/adapters/primaries/user.proto b/src/modules/users/adapters/primaries/user.proto index e59db4b..6955c19 100644 --- a/src/modules/users/adapters/primaries/user.proto +++ b/src/modules/users/adapters/primaries/user.proto @@ -7,6 +7,7 @@ service UsersService { rpc FindAll(UserFilter) returns (Users); rpc Create(User) returns (User); rpc Update(User) returns (User); + rpc Delete(UserByUuid) returns (Empty); } message UserByUuid { @@ -25,3 +26,5 @@ message UserFilter {} message Users { repeated User users = 1; } + +message Empty {} diff --git a/src/modules/users/adapters/primaries/users.controller.ts b/src/modules/users/adapters/primaries/users.controller.ts index 697c99e..df5636f 100644 --- a/src/modules/users/adapters/primaries/users.controller.ts +++ b/src/modules/users/adapters/primaries/users.controller.ts @@ -5,6 +5,7 @@ import { CommandBus, QueryBus } from '@nestjs/cqrs'; import { GrpcMethod, RpcException } from '@nestjs/microservices'; 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'; @@ -71,4 +72,26 @@ export class UsersController { throw new RpcException({}); } } + + @GrpcMethod('UsersService', 'Delete') + async deleteUser(data: FindUserByUuidRequest): Promise { + 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({}); + } + } } diff --git a/src/modules/users/commands/delete-user.command.ts b/src/modules/users/commands/delete-user.command.ts new file mode 100644 index 0000000..2e69a67 --- /dev/null +++ b/src/modules/users/commands/delete-user.command.ts @@ -0,0 +1,7 @@ +export class DeleteUserCommand { + readonly uuid: string; + + constructor(uuid: string) { + this.uuid = uuid; + } +} diff --git a/src/modules/users/domain/usecases/delete-user.usecase.ts b/src/modules/users/domain/usecases/delete-user.usecase.ts new file mode 100644 index 0000000..4378b61 --- /dev/null +++ b/src/modules/users/domain/usecases/delete-user.usecase.ts @@ -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 { + return this._repository.delete(command.uuid); + } +} diff --git a/src/modules/users/tests/unit/delete-user.usecase.spec.ts b/src/modules/users/tests/unit/delete-user.usecase.spec.ts new file mode 100644 index 0000000..b88fd9f --- /dev/null +++ b/src/modules/users/tests/unit/delete-user.usecase.spec.ts @@ -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); + }); + + 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(); + }); + }); +}); diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 01a8bd5..2668167 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -4,6 +4,7 @@ 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'; @@ -17,6 +18,7 @@ import { UserProfile } from './mappers/user.profile'; FindUserByUuidUseCase, CreateUserUseCase, UpdateUserUseCase, + DeleteUserUseCase, ], exports: [], })