diff --git a/src/users/dtos/listUsersQuery.dto.ts b/src/users/dtos/listUsersQuery.dto.ts new file mode 100644 index 0000000..0f626f1 --- /dev/null +++ b/src/users/dtos/listUsersQuery.dto.ts @@ -0,0 +1,22 @@ +import { IsEmail, IsNotEmpty, IsOptional } from 'class-validator'; + +export class ListUsersQueryDto { + @IsEmail() + @IsOptional() + email?: string; + + @IsOptional() + firstName?: string; + + @IsOptional() + lastName?: string; + + @IsOptional() + phone?: string; + + @IsNotEmpty() + perPage: number; + + @IsNotEmpty() + page: number; +} diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 03b48eb..0fa8c9a 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -8,12 +8,14 @@ import { Put, UseGuards, Request, + Query, } from '@nestjs/common'; import { UpdateUserDto } from './dtos/updateUser.dto'; import { AuthGuard } from '../auth/auth.guard'; import { Roles } from '../auth/roles.decorator'; import { UserRoles } from '../database/entities/user.entity'; import { RolesGuard } from '../auth/roles.guard'; +import { ListUsersQueryDto } from './dtos/listUsersQuery.dto'; @Controller('users') export class UsersController { @@ -22,8 +24,8 @@ export class UsersController { @Roles(UserRoles.Admin) @UseGuards(AuthGuard, RolesGuard) @Get() - findAll() { - return this.usersService.findAll(); + findAll(@Query() query: ListUsersQueryDto) { + return this.usersService.findAll(query); } @Get(':id') diff --git a/src/users/users.service.spec.ts b/src/users/users.service.spec.ts index e173e21..696d5e6 100644 --- a/src/users/users.service.spec.ts +++ b/src/users/users.service.spec.ts @@ -15,6 +15,7 @@ jest.mock('bcrypt', () => ({ const repositoryMockFactory = () => ({ find: jest.fn(), findOneBy: jest.fn(), + findAndCount: jest.fn(), save: jest.fn(), delete: jest.fn(), }); @@ -41,11 +42,19 @@ describe('UsersService', () => { describe('findAll', () => { it('should return an array of users', async () => { const users = [new User(), new User()]; - jest.spyOn(userRepository, 'find').mockResolvedValueOnce(users); + jest + .spyOn(userRepository, 'findAndCount') + .mockResolvedValueOnce([users, 2]); - const result = await service.findAll(); - expect(result).toEqual(users); - expect(userRepository.find).toHaveBeenCalledTimes(1); + const result = await service.findAll({ + perPage: 10, + page: 0, + }); + expect(result).toEqual({ + items: users, + total: 2, + }); + expect(userRepository.findAndCount).toHaveBeenCalledTimes(1); }); }); diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 8b8e3d0..28aead7 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -8,6 +8,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from '../database/entities/user.entity'; import * as bcrypt from 'bcrypt'; +import { ListUsersQueryDto } from './dtos/listUsersQuery.dto'; @Injectable() export class UsersService { @@ -16,8 +17,30 @@ export class UsersService { private usersRepository: Repository, ) {} - findAll(): Promise { - return this.usersRepository.find(); + async findAll(query: ListUsersQueryDto): Promise<{ + items: User[]; + total: number; + }> { + const whereConditions = {}; + if (query.email) whereConditions['email'] = query.email; + if (query.firstName) whereConditions['firstName'] = query.firstName; + if (query.lastName) whereConditions['lastName'] = query.lastName; + if (query.phone) whereConditions['phone'] = query.phone; + + const take = query.perPage || 10; + const skip = query.page || 0; + + const [result, total] = await this.usersRepository.findAndCount({ + where: whereConditions, + take: take, + skip: skip, + order: { createdAt: 'DESC' }, + }); + + return { + items: result, + total, + }; } findOne(id: string): Promise {