I'm getting: TypeError: Cannot read property 'list' of undefined (my custom repository BeneficiosRepository) The problem is for the same instance of this service (BeneficiosService), the create and update function works, but pageAll, findOne and delete do not. I can't understand the reason I did a test forcing the create function to call the pageAll and it worked.
My Module:
@Module({
imports: [TypeOrmModule.forFeature([Beneficio,]), forwardRef(() => UsersModule)],
controllers: [BeneficiosController],
providers: [BeneficiosService, BeneficiosRepository, IsUniqueNomeConstraint],
exports: [BeneficiosService, BeneficiosRepository],
})
export class BeneficiosModule { }
My Service:
@Injectable({ scope: Scope.REQUEST })
export class BeneficiosService {
constructor(
@Inject(REQUEST)
private readonly request: Request,
private beneficiosRepository: BeneficiosRepository,
@Inject(forwardRef(() => UsersService))
private readonly usersService: UsersService,
) {
}
@UseInterceptors(ClassSerializerInterceptor)
async pageAll(pageOptionsDto: PageOptionsDto, filterDto: FilterBeneficioDto) {
const [beneficios, total] = await this.beneficiosRepository.list(pageOptionsDto, filterDto);
const pageMetaDto = new PageMetaDto({ itemCount: total, pageOptionsDto });
return new PageDto(beneficios, pageMetaDto);
}
@UseInterceptors(ClassSerializerInterceptor)
async create(dto: CreateBeneficioDto) {
const validatedDto = this.validationDesconto(dto);
const user_id = getUserIdService(this.request);
const user = await this.usersService.findOne(user_id);
const beneficio = this.beneficiosRepository.create(validatedDto);
beneficio.user_registrou = user;
const createdBeneficio = await this.beneficiosRepository.save(beneficio);
return plainToClass(Beneficio, createdBeneficio);
}
@UseInterceptors(ClassSerializerInterceptor)
async findOne(id: string) {
const beneficioExists = await this.checkIfBeneficioExists(id);
return instanceToPlain(beneficioExists, { groups: ['find'] }) as Beneficio;
}
@UseInterceptors(ClassSerializerInterceptor)
async update(id: string, dto: UpdateBeneficioDto) {
const validatedDto = this.validationDesconto(dto);
await this.checkIfBeneficioExists(id);
const updatedBeneficio = await this.beneficiosRepository.save(validatedDto);
return plainToClass(Beneficio, updatedBeneficio);
}
@UseInterceptors(ClassSerializerInterceptor)
async remove(id: string) {
await this.checkIfBeneficioExists(id);
await this.beneficiosRepository.softDelete({ id });
}
async findByIds(ids: string[]) {
return await this.beneficiosRepository.findBy({ id: In(ids) });
}
private async checkIfBeneficioExists(id: string): Promise<Beneficio> {
const beneficioExists = await this.beneficiosRepository.findById(id);
if (!beneficioExists) {
throw new AppError(`Benefício ${id} não encontrado!`, 404);
}
return beneficioExists;
}
private validationDesconto(beneficio: Beneficio | UpdateBeneficioDto | CreateBeneficioDto): Beneficio | UpdateBeneficioDto | CreateBeneficioDto {
const { is_descontado, tipo_desconto, valor_desconto } = beneficio;
if (!is_descontado) {
delete beneficio.tipo_desconto;
delete beneficio.valor_desconto;
return beneficio;
}
if (tipo_desconto && valor_desconto && valor_desconto.valueOf()) {
return beneficio;
}
throw new AppError(`Se o benefício é descontado, os campos "tipo_desconto" e "valor_desconto" devem obrigatóriamente serem preenchidos!`);
}
}
My Controller:
@ApiBearerAuth()
@ApiTags('beneficios')
@Controller('beneficios')
export class BeneficiosController {
constructor(private readonly beneficiosService: BeneficiosService) { }
@Post()
@ApiOperation({ summary: 'Cria um novo benefício' })
@ApiResponse({ status: 200, isArray: false, type: Beneficio })
@ApiResponse({ status: 403, description: 'Proibido.' })
async create(@Body() dto: CreateBeneficioDto) {
return await this.beneficiosService.create(dto);
}
@Get()
@ApiOperation({ summary: 'Lista todos os benefícios ativos' })
@ApiResponse({ status: 200, isArray: true, type: Beneficio })
@ApiResponse({ status: 403, description: 'Proibido.' })
async pageAll(@Query() dto: PageOptionsDto, @Query() filter: FilterBeneficioDto) {
return await this.beneficiosService.pageAll(dto, filter);
}
@Get(':id')
@ApiOperation({ summary: 'Recupera um benefício com base no ID passado' })
@ApiResponse({ status: 200, isArray: false, type: Beneficio })
@ApiResponse({ status: 403, description: 'Proibido.' })
findOne(@Param('id') id: string) {
return this.beneficiosService.findOne(id);
}
@Put(':id')
@ApiOperation({ summary: 'Atualiza um benefício' })
@ApiResponse({ status: 200, isArray: false, type: Beneficio })
@ApiResponse({ status: 403, description: 'Proibido.' })
update(@Param('id',) id: string, @Body() dto: UpdateBeneficioDto) {
return this.beneficiosService.update(id, dto);
}
@Delete(':id')
@ApiOperation({ summary: 'Deleta um benefício' })
@ApiResponse({ status: 204, })
@ApiResponse({ status: 403, description: 'Proibido.' })
remove(@Param('id') id: string) {
return this.beneficiosService.remove(id);
}
}
My Repo:
@Injectable()
export class BeneficiosRepository extends Repository<Beneficio> implements IBeneficiosRepository {
constructor(private dataSource: DataSource) {
super(Beneficio, dataSource.createEntityManager());
}
async findById(id: string): Promise<Beneficio> {
const beneficio = await this
.createQueryBuilder("beneficio")
.leftJoinAndSelect("beneficio.user_registrou", "users")
.where("beneficio.id = :id", { id })
.getOne();
return beneficio;
}
async findByNome(nome: string): Promise<Beneficio> {
const beneficio = await this
.createQueryBuilder("beneficio")
.leftJoinAndSelect("beneficio.user_registrou", "users")
.where("beneficio.nome ILIKE :nome", { nome })
.getOne();
return beneficio;
}
async list({ skip, take, order }: PageOptionsDto,
{ tipo_desconto, is_descontado, descricao, nome }: FilterBeneficioDto): Promise<[Beneficio[], number]> {
const query = this
.createQueryBuilder("beneficio")
.orderBy("beneficio.created_at", order)
.skip(skip)
.take(take)
.where("1=1");
if (nome) {
query.andWhere("beneficio.nome ILIKE :nome", { nome: '%${nome}%'});
}
if (descricao) {
query.andWhere("beneficio.descricao ILIKE :descricao", { descricao: '%${descricao}%' });
}
if (is_descontado && is_descontado === 'true' || is_descontado === 'false') {
query.andWhere("beneficio.is_descontado = :is_descontado", { is_descontado });
}
if (tipo_desconto) {
query.andWhere("beneficio.tipo_desconto = :tipo_desconto", { tipo_desconto });
}
const beneficios = await query.getManyAndCount();
return beneficios;
}
}
Resource http://localhost:3000/beneficios - Method POST = Work Print success
Resource http://localhost:3000/beneficios - Method GET = Repository is undefined Print error
Testing via Insomnia
Work:
@UseInterceptors(ClassSerializerInterceptor)
async create(dto: CreateBeneficioDto) {
return await this.pageAll({skip: 0}, {});
}
Undefined Error:
@UseInterceptors(ClassSerializerInterceptor)
async pageAll(pageOptionsDto: PageOptionsDto, filterDto: FilterBeneficioDto) {
const [beneficios, total] = await this.beneficiosRepository.list(pageOptionsDto, filterDto);
const pageMetaDto = new PageMetaDto({ itemCount: total, pageOptionsDto });
return new PageDto(beneficios, pageMetaDto);
}