import { BadRequestException, HttpStatus, Injectable } from '@nestjs/common'; import { Repository } from 'typeorm'; import { ResultRange } from '../entities/result-range.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { CreateResultRangeDTO } from '../dtos/create-result-range.dto'; import { AppTimeoutException } from '@/common/exceptions/app-timeout.exception'; import { AppException } from '@/common/exceptions/app.exception'; import { TestsService } from '@/modules/tests/providers/tests.service'; import { AppResponse } from '@/common/responses'; import { I18nService } from 'nestjs-i18n'; import { UpdateResultRangeDTO } from '../dtos/update-result-range.dto'; @Injectable() export class ResultRangeCommandProvider { constructor( /** * Inject ResultRange Repository */ @InjectRepository(ResultRange) private readonly resultRangeRepository: Repository, /** * Inject Tests Service */ private readonly testsService: TestsService, /** * Inject I18n Service */ private readonly i18nService: I18nService, ) {} private async checkRangeOverlap( test: number, minScore: number, maxScore: number, excludeSelf: boolean = false, ): Promise { const queryBuilder = this.resultRangeRepository .createQueryBuilder('resultRange') .where('resultRange.testId = :test', { test }) .andWhere( '(resultRange.minScore BETWEEN :minScore AND :maxScore) OR (resultRange.maxScore BETWEEN :minScore AND :maxScore) OR (:minScore BETWEEN resultRange.minScore AND resultRange.maxScore) OR (:maxScore BETWEEN resultRange.minScore AND resultRange.maxScore)', { minScore, maxScore }, ); let overlappingRanges: Array; try { overlappingRanges = await queryBuilder.getMany(); } catch (err) { throw new AppTimeoutException(err); } if (overlappingRanges.length > (excludeSelf ? 1 : 0)) { throw new AppException( 'scoring.errors.resultRangeOverlappingConstraint', HttpStatus.CONFLICT, ); } } private async checkResultRangeExistance(resultRangeId: number) { let resultRange: ResultRange | null = null; try { resultRange = await this.resultRangeRepository.findOne({ where: { id: resultRangeId, }, relations: { test: true, }, }); } catch (err) { throw new AppTimeoutException(err); } if (!resultRange) { throw new AppException( 'common.errors.entityNotFound', HttpStatus.NOT_FOUND, { entity: '$t(scoring.fields.resultRange)' }, ); } return resultRange; } public async createOne(createResultRangeDto: CreateResultRangeDTO) { const test = await this.testsService.adminGetOne(createResultRangeDto.test); await this.checkRangeOverlap( test.id, createResultRangeDto.minScore, createResultRangeDto.maxScore, ); const newResultRange = this.resultRangeRepository.create({ ...createResultRangeDto, test, }); try { await this.resultRangeRepository.save(newResultRange); return new AppResponse( newResultRange, this.i18nService.translate('common.messages.createSuccess', { args: { entity: '$t(scoring.fields.resultRange)' }, }), ); } catch (err) { throw new AppTimeoutException(err); } } public async updateOne( id: number, updateResultRangeDto: UpdateResultRangeDTO, ) { const resultRange = await this.checkResultRangeExistance(id); if (updateResultRangeDto.test) { await this.testsService.adminGetOne(updateResultRangeDto.test); } const testId = updateResultRangeDto.test !== undefined ? updateResultRangeDto.test : resultRange.test.id; const minScore = updateResultRangeDto.minScore !== undefined ? updateResultRangeDto.minScore : resultRange.minScore; const maxScore = updateResultRangeDto.maxScore !== undefined ? updateResultRangeDto.maxScore : resultRange.maxScore; if (minScore >= maxScore) { throw new BadRequestException( 'scoring.errors.resultRangeMinMaxConstraint', ); } await this.checkRangeOverlap(testId, minScore, maxScore, true); Object.assign(resultRange, updateResultRangeDto); try { return await this.resultRangeRepository.save(resultRange); } catch (err) { throw new AppTimeoutException(err); } } public async deleteOne(id: number) { const resultRange = await this.checkResultRangeExistance(id); try { await this.resultRangeRepository.delete(resultRange.id); } catch (err) { throw new AppTimeoutException(err); } } }