Files
heala-backend/src/modules/questions/providers/transition/validations/check-transition-db.provider.ts
T

172 lines
4.8 KiB
TypeScript

import { AppException } from '@/common/exceptions/app.exception';
import { QuestionTransition } from '@/modules/questions/entities/question-transition.entity';
import { QuestionTransitionType } from '@/modules/questions/enums/question-transition-type.enum';
import { NumericCondition } from '@/modules/questions/interfaces/numeric-condition.interface';
import { SingleChoiceCondition } from '@/modules/questions/interfaces/single-choice-condition.interface';
import { TransitionValidateOptions } from '@/modules/questions/interfaces/transition-validate-options.interface';
import { HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import type { Repository } from 'typeorm';
@Injectable()
export class CheckTransitionDBProvider {
constructor(
/**
* Inject Transitions Repository
*/
@InjectRepository(QuestionTransition)
private readonly transitionsRepository: Repository<QuestionTransition>,
) {}
public async validate(
options: TransitionValidateOptions,
transitionId?: number,
) {
await this.validateSingleStart(options, transitionId);
await this.validateSingleEnd(options, transitionId);
await this.validateDefaultTransition(options, transitionId);
await this.validateDuplicateCondition(options, transitionId);
}
private async validateSingleStart(
options: TransitionValidateOptions,
transitionId?: number,
) {
if (options.type !== QuestionTransitionType.START) return;
const qb = this.transitionsRepository
.createQueryBuilder('t')
.where('t.testId = :testId', {
testId: options.test.id,
})
.andWhere('t.type = :type', {
type: QuestionTransitionType.START,
});
if (transitionId) {
qb.andWhere('t.id != :transitionId', {
transitionId,
});
}
if (await qb.getExists()) {
throw new AppException(
'questions.errors.questionTransition.startAlreadyExists',
HttpStatus.CONFLICT,
);
}
}
private async validateSingleEnd(
options: TransitionValidateOptions,
transitionId?: number,
) {
if (options.type !== QuestionTransitionType.END) return;
const qb = this.transitionsRepository
.createQueryBuilder('t')
.where('t.fromQuestionId = :fromQuestionId', {
fromQuestionId: options.fromQuestion?.id,
})
.andWhere('t.type = :type', {
type: QuestionTransitionType.END,
});
if (transitionId) {
qb.andWhere('t.id != :transitionId', {
transitionId,
});
}
if (await qb.getExists()) {
throw new AppException(
'questions.errors.questionTransition.endAlreadyExists',
HttpStatus.CONFLICT,
);
}
}
private async validateDefaultTransition(
options: TransitionValidateOptions,
transitionId?: number,
) {
if (options.type !== QuestionTransitionType.DEFAULT) return;
const qb = this.transitionsRepository
.createQueryBuilder('t')
.where('t.fromQuestionId = :fromQuestionId', {
fromQuestionId: options.fromQuestion?.id,
})
.andWhere('t.type = :type', {
type: QuestionTransitionType.DEFAULT,
});
if (transitionId) {
qb.andWhere('t.id != :transitionId', {
transitionId,
});
}
if (await qb.getExists()) {
throw new AppException(
'questions.errors.questionTransition.defaultAlreadyExists',
HttpStatus.CONFLICT,
);
}
}
private async validateDuplicateCondition(
options: TransitionValidateOptions,
transitionId?: number,
) {
if (
options.type === QuestionTransitionType.DEFAULT ||
options.type === QuestionTransitionType.START ||
options.type === QuestionTransitionType.END
) {
return;
}
const qb = this.transitionsRepository
.createQueryBuilder('t')
.where('t.fromQuestionId = :fromQuestionId', {
fromQuestionId: options.fromQuestion?.id,
})
.andWhere('t.type = :type', {
type: options.type,
});
if (options.type === QuestionTransitionType.CHOICE) {
qb.andWhere(`t.conditionValue ->> 'choiceId' = :choiceId`, {
choiceId: String(
(options.conditionValue as SingleChoiceCondition).choiceId,
),
});
}
if (options.type === QuestionTransitionType.NUMBER_RANGE) {
qb.andWhere(`t.conditionValue ->> 'min' = :min`, {
min: String((options.conditionValue as NumericCondition).min),
}).andWhere(`t.conditionValue ->> 'max' = :max`, {
max: String((options.conditionValue as NumericCondition).max),
});
}
if (transitionId) {
qb.andWhere('t.id != :transitionId', {
transitionId,
});
}
if (await qb.getExists()) {
throw new AppException(
'questions.errors.questionTransition.duplicateTransition',
HttpStatus.CONFLICT,
);
}
}
}