diff --git a/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts b/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts index 7e750c4..b8f170d 100644 --- a/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts +++ b/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts @@ -1,6 +1,7 @@ import { ConsoleLogger, Injectable } from '@nestjs/common'; import { PrismaClientKnownRequestError } from '@prisma/client/runtime'; import { DatabaseException } from '../../exceptions/DatabaseException'; +import { ICollection } from '../../interfaces/collection.interface'; import { IRepository } from '../../interfaces/repository.interface'; import { PrismaService } from './prisma-service'; @@ -14,24 +15,27 @@ export abstract class PrismaRepository implements IRepository { constructor(protected readonly _prisma: PrismaService) {} - findAll(where?: any, include?: any): Promise { - return this._prisma[this._model].findMany({ where, include }); - } - - async findOneById(id: number, include?: any): Promise { - try { - const entity = await this._prisma[this._model].findUnique({ - where: { id }, - }); - - return entity; - } catch (e) { - if (e instanceof PrismaClientKnownRequestError) { - throw new DatabaseException(PrismaClientKnownRequestError.name, e.code); - } else { - throw new DatabaseException(); - } - } + async findAll( + page = 1, + perPage = 10, + where?: any, + include?: any, + ): Promise> { + const [data, total] = await this._prisma.$transaction([ + this._prisma[this._model].findMany({ + where, + include, + skip: (page - 1) * perPage, + take: perPage, + }), + this._prisma[this._model].count({ + where, + }), + ]); + return Promise.resolve({ + data, + total, + }); } async findOneByUuid(uuid: string, include?: any): Promise { diff --git a/src/modules/database/src/interfaces/collection.interface.ts b/src/modules/database/src/interfaces/collection.interface.ts new file mode 100644 index 0000000..6e9a96d --- /dev/null +++ b/src/modules/database/src/interfaces/collection.interface.ts @@ -0,0 +1,4 @@ +export interface ICollection { + data: T[]; + total: number; +} diff --git a/src/modules/database/src/interfaces/repository.interface.ts b/src/modules/database/src/interfaces/repository.interface.ts index 70fd241..1755f33 100644 --- a/src/modules/database/src/interfaces/repository.interface.ts +++ b/src/modules/database/src/interfaces/repository.interface.ts @@ -1,5 +1,12 @@ +import { ICollection } from './collection.interface'; + export interface IRepository { - findAll(params?: any, include?: any): Promise; + findAll( + page: number, + perPage: number, + params?: any, + include?: any, + ): Promise>; findOne(where: any, include?: any): Promise; findOneByUuid(uuid: string, include?: any): Promise; create(entity: Partial | any, include?: any): Promise; diff --git a/src/modules/users/adapters/primaries/user.proto b/src/modules/users/adapters/primaries/user.proto index 6955c19..cf8979c 100644 --- a/src/modules/users/adapters/primaries/user.proto +++ b/src/modules/users/adapters/primaries/user.proto @@ -21,10 +21,14 @@ message User { string email = 4; } -message UserFilter {} +message UserFilter { + optional int32 page = 1; + optional int32 perPage = 2; +} message Users { - repeated User users = 1; + repeated User data = 1; + int32 total = 2; } message Empty {} diff --git a/src/modules/users/adapters/primaries/users.controller.ts b/src/modules/users/adapters/primaries/users.controller.ts index df5636f..cd09284 100644 --- a/src/modules/users/adapters/primaries/users.controller.ts +++ b/src/modules/users/adapters/primaries/users.controller.ts @@ -8,11 +8,14 @@ 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 { FindAllUsersRequest } from '../../domain/dto/find-all-users.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 { FindAllUsersQuery } from '../../queries/find-all-users.query'; import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query'; import { UserPresenter } from './user.presenter'; +import { ICollection } from '../../../database/src/interfaces/collection.interface'; @Controller() export class UsersController { @@ -22,6 +25,19 @@ export class UsersController { @InjectMapper() private readonly _mapper: Mapper, ) {} + @GrpcMethod('UsersService', 'FindAll') + async findAll(data: FindAllUsersRequest): Promise> { + const userCollection = await this._queryBus.execute( + new FindAllUsersQuery(data), + ); + return Promise.resolve({ + data: userCollection.data.map((user: User) => + this._mapper.map(user, User, UserPresenter), + ), + total: userCollection.total, + }); + } + @GrpcMethod('UsersService', 'FindOneByUuid') async findOneByUuid(data: FindUserByUuidRequest): Promise { const user = await this._queryBus.execute( diff --git a/src/modules/users/domain/dto/find-all-users.request.ts b/src/modules/users/domain/dto/find-all-users.request.ts new file mode 100644 index 0000000..d01f8e0 --- /dev/null +++ b/src/modules/users/domain/dto/find-all-users.request.ts @@ -0,0 +1,11 @@ +import { IsInt, IsOptional } from 'class-validator'; + +export class FindAllUsersRequest { + @IsInt() + @IsOptional() + page?: number; + + @IsInt() + @IsOptional() + perPage?: number; +} diff --git a/src/modules/users/domain/usecases/find-all-users.usecase.ts b/src/modules/users/domain/usecases/find-all-users.usecase.ts new file mode 100644 index 0000000..df2608f --- /dev/null +++ b/src/modules/users/domain/usecases/find-all-users.usecase.ts @@ -0,0 +1,19 @@ +import { QueryHandler } from '@nestjs/cqrs'; +import { ICollection } from 'src/modules/database/src/interfaces/collection.interface'; +import { UsersRepository } from '../../adapters/secondaries/users.repository'; +import { FindAllUsersQuery } from '../../queries/find-all-users.query'; +import { User } from '../entities/user'; + +@QueryHandler(FindAllUsersQuery) +export class FindAllUsersUseCase { + constructor(private readonly _usersRepository: UsersRepository) {} + + async execute( + findAllUsersQuery: FindAllUsersQuery, + ): Promise> { + return this._usersRepository.findAll( + findAllUsersQuery.page, + findAllUsersQuery.perPage, + ); + } +} diff --git a/src/modules/users/queries/find-all-users.query.ts b/src/modules/users/queries/find-all-users.query.ts new file mode 100644 index 0000000..f33ecb8 --- /dev/null +++ b/src/modules/users/queries/find-all-users.query.ts @@ -0,0 +1,11 @@ +import { FindAllUsersRequest } from '../domain/dto/find-all-users.request'; + +export class FindAllUsersQuery { + page: number; + perPage: number; + + constructor(findAllUsersRequest?: FindAllUsersRequest) { + this.page = findAllUsersRequest?.page ?? 1; + this.perPage = findAllUsersRequest?.perPage ?? 10; + } +} diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 2668167..10a82a9 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -5,6 +5,7 @@ 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 { FindAllUsersUseCase } from './domain/usecases/find-all-users.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'; @@ -15,6 +16,7 @@ import { UserProfile } from './mappers/user.profile'; providers: [ UserProfile, UsersRepository, + FindAllUsersUseCase, FindUserByUuidUseCase, CreateUserUseCase, UpdateUserUseCase,