Files
heala-backend/src/modules/scoring/providers/result-range-command.provider.ts
T

169 lines
4.7 KiB
TypeScript

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<ResultRange>,
/**
* 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<void> {
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<ResultRange>;
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);
}
}
}