findUserById
This commit is contained in:
parent
cc170779cb
commit
979ea5e98f
|
@ -0,0 +1,17 @@
|
||||||
|
import { IQueryHandler, QueryHandler } from '@nestjs/cqrs';
|
||||||
|
import { FindUserByIdQuery } from './find-user-by-id.query';
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { USER_REPOSITORY } from '@modules/user/user.di-tokens';
|
||||||
|
import { UserRepositoryPort } from '../../ports/user.repository.port';
|
||||||
|
import { UserEntity } from '@modules/user/core/domain/user.entity';
|
||||||
|
|
||||||
|
@QueryHandler(FindUserByIdQuery)
|
||||||
|
export class FindUserByIdQueryHandler implements IQueryHandler {
|
||||||
|
constructor(
|
||||||
|
@Inject(USER_REPOSITORY)
|
||||||
|
private readonly userRepository: UserRepositoryPort,
|
||||||
|
) {}
|
||||||
|
async execute(query: FindUserByIdQuery): Promise<UserEntity> {
|
||||||
|
return await this.userRepository.findOneById(query.id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { QueryBase } from '@mobicoop/ddd-library';
|
||||||
|
|
||||||
|
export class FindUserByIdQuery extends QueryBase {
|
||||||
|
readonly id: string;
|
||||||
|
|
||||||
|
constructor(id: string) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class FindUserByIdRequestDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
id: string;
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Controller, UsePipes } from '@nestjs/common';
|
||||||
|
import { QueryBus } from '@nestjs/cqrs';
|
||||||
|
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||||
|
import { NotFoundException } from '@mobicoop/ddd-library';
|
||||||
|
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||||
|
import { RpcValidationPipe } from '@mobicoop/ddd-library';
|
||||||
|
import { UserMapper } from '@modules/user/user.mapper';
|
||||||
|
import { FindUserByIdRequestDto } from './dtos/find-user-by-id.request.dto';
|
||||||
|
import { UserResponseDto } from '../dtos/user.response.dto';
|
||||||
|
import { UserEntity } from '@modules/user/core/domain/user.entity';
|
||||||
|
import { FindUserByIdQuery } from '@modules/user/core/application/queries/find-user-by-id/find-user-by-id.query';
|
||||||
|
|
||||||
|
@UsePipes(
|
||||||
|
new RpcValidationPipe({
|
||||||
|
whitelist: false,
|
||||||
|
forbidUnknownValues: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
@Controller()
|
||||||
|
export class FindUserByIdGrpcController {
|
||||||
|
constructor(
|
||||||
|
protected readonly mapper: UserMapper,
|
||||||
|
private readonly queryBus: QueryBus,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@GrpcMethod('UserService', 'FindOneById')
|
||||||
|
async findOnebyId(data: FindUserByIdRequestDto): Promise<UserResponseDto> {
|
||||||
|
try {
|
||||||
|
const user: UserEntity = await this.queryBus.execute(
|
||||||
|
new FindUserByIdQuery(data.id),
|
||||||
|
);
|
||||||
|
return this.mapper.toResponse(user);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof NotFoundException) {
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcExceptionCode.NOT_FOUND,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcExceptionCode.UNKNOWN,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { UserEntity } from '@modules/user/core/domain/user.entity';
|
||||||
|
import { FindUserByIdQueryHandler } from '@modules/user/core/application/queries/find-user-by-id/find-user-by-id.query-handler';
|
||||||
|
import { USER_REPOSITORY } from '@modules/user/user.di-tokens';
|
||||||
|
import { FindUserByIdQuery } from '@modules/user/core/application/queries/find-user-by-id/find-user-by-id.query';
|
||||||
|
|
||||||
|
const now = new Date('2023-06-21 06:00:00');
|
||||||
|
const user: UserEntity = new UserEntity({
|
||||||
|
id: 'c160cf8c-f057-4962-841f-3ad68346df44',
|
||||||
|
props: {
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
email: 'john.doe@email.com',
|
||||||
|
phone: '+33611223344',
|
||||||
|
},
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockUserRepository = {
|
||||||
|
findOneById: jest.fn().mockImplementation(() => user),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('find-user-by-id.query-handler', () => {
|
||||||
|
let findUserByIdQueryHandler: FindUserByIdQueryHandler;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: USER_REPOSITORY,
|
||||||
|
useValue: mockUserRepository,
|
||||||
|
},
|
||||||
|
FindUserByIdQueryHandler,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
findUserByIdQueryHandler = module.get<FindUserByIdQueryHandler>(
|
||||||
|
FindUserByIdQueryHandler,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(findUserByIdQueryHandler).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('execution', () => {
|
||||||
|
it('should return a user', async () => {
|
||||||
|
const findUserbyIdQuery = new FindUserByIdQuery(
|
||||||
|
'dd264806-13b4-4226-9b18-87adf0ad5dd1',
|
||||||
|
);
|
||||||
|
const user: UserEntity = await findUserByIdQueryHandler.execute(
|
||||||
|
findUserbyIdQuery,
|
||||||
|
);
|
||||||
|
expect(user.getProps().lastName).toBe('Doe');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,103 @@
|
||||||
|
import { NotFoundException } from '@mobicoop/ddd-library';
|
||||||
|
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||||
|
import { FindUserByIdGrpcController } from '@modules/user/interface/grpc-controllers/find-user-by-id.grpc.controller';
|
||||||
|
import { UserMapper } from '@modules/user/user.mapper';
|
||||||
|
import { QueryBus } from '@nestjs/cqrs';
|
||||||
|
import { RpcException } from '@nestjs/microservices';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
|
||||||
|
const mockQueryBus = {
|
||||||
|
execute: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementationOnce(() => '200d61a8-d878-4378-a609-c19ea71633d2')
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw new NotFoundException();
|
||||||
|
})
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
throw new Error();
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockUserMapper = {
|
||||||
|
toResponse: jest.fn().mockImplementationOnce(() => ({
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
email: 'john.doe@email.com',
|
||||||
|
phone: '+33611223344',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Find User By Id Grpc Controller', () => {
|
||||||
|
let findUserbyIdGrpcController: FindUserByIdGrpcController;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: QueryBus,
|
||||||
|
useValue: mockQueryBus,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: UserMapper,
|
||||||
|
useValue: mockUserMapper,
|
||||||
|
},
|
||||||
|
FindUserByIdGrpcController,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
findUserbyIdGrpcController = module.get<FindUserByIdGrpcController>(
|
||||||
|
FindUserByIdGrpcController,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(findUserbyIdGrpcController).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a user', async () => {
|
||||||
|
jest.spyOn(mockQueryBus, 'execute');
|
||||||
|
jest.spyOn(mockUserMapper, 'toResponse');
|
||||||
|
const response = await findUserbyIdGrpcController.findOnebyId({
|
||||||
|
id: '6dcf093c-c7db-4dae-8e9c-c715cebf83c7',
|
||||||
|
});
|
||||||
|
expect(response.firstName).toBe('John');
|
||||||
|
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockUserMapper.toResponse).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw a dedicated RpcException if user is not found', async () => {
|
||||||
|
jest.spyOn(mockQueryBus, 'execute');
|
||||||
|
jest.spyOn(mockUserMapper, 'toResponse');
|
||||||
|
expect.assertions(4);
|
||||||
|
try {
|
||||||
|
await findUserbyIdGrpcController.findOnebyId({
|
||||||
|
id: 'ac85f5f4-41cd-4c5d-9aee-0a1acb176fb8',
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
expect(e).toBeInstanceOf(RpcException);
|
||||||
|
expect(e.error.code).toBe(RpcExceptionCode.NOT_FOUND);
|
||||||
|
}
|
||||||
|
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockUserMapper.toResponse).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw a generic RpcException', async () => {
|
||||||
|
jest.spyOn(mockQueryBus, 'execute');
|
||||||
|
jest.spyOn(mockUserMapper, 'toResponse');
|
||||||
|
expect.assertions(4);
|
||||||
|
try {
|
||||||
|
await findUserbyIdGrpcController.findOnebyId({
|
||||||
|
id: '53c8e7ec-ef68-42bc-ba4c-5ef3effa60a6',
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
expect(e).toBeInstanceOf(RpcException);
|
||||||
|
expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN);
|
||||||
|
}
|
||||||
|
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockUserMapper.toResponse).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue