import { SafePromise, Exception } from "@rolesvillesoftware/tools/dist"; import { Connection } from "@rolesvillesoftware/tsentity/dist"; import { ExamContext, ExamDim, ExamStat, ExamFact, QuestionStat } from "../models"; import { Calculator, ExamCalculator, QuestionsCalculator, QuestionCalculator } from "./"; import { Logger } from "../Logger"; /** * PEV Main Calculator - Calculates exams and PEV scores * * @export * @class PevCalculator * @extends {Calculator} */ export class PevCalculator extends Calculator { /** * * * @param {number} [input] Option parameter to only run Exam scores for one particular exam * @returns {Promise} Promise when completed will return any messages generated by Calculation process * @memberof PevCalculator */ async calculate(input?: number): Promise { Logger.log("Starting PEV Calculations"); const exams = this.processResults(await SafePromise.run(() => this.getExams(input))); Logger.log(`Exams to be processed: ${exams.length}`); for (const exam of exams) { Logger.log(`Processing Exam ${exam.id} - ${exam.name}`); const examStat = await SafePromise.run(() => this.calcExamStats(exam)); if (examStat.isError) { const attached = this.context["_attached"].filter(item => item.isDirty); if (attached != null || attached.length > 0) { attached.forEach(item => item.setCleaned()); } exam.pevStatus = "E"; exam.pevMessage = `${JSON.stringify(examStat.error)}`; if (exam.pevMessage.length > 4000) { exam.pevMessage = exam.pevMessage.substr(0, 4000); } this.processResults(await SafePromise.run(() => this.context.saveChanges())); } Logger.log(`Cleaning up -> Dispatch attached: ${this.context["_attached"].count}`); this.context["_attached"].filter(item => item["_entity"]["tableName"] !== "ExamDim").forEach(element => this.context["_attached"].remove(element)); Logger.log(`Completed -> Dispatch attached: ${this.context["_attached"].count}`); } return []; } /** * Get the exams that still need to be scored. * * @param {number} [examId] Get a single exam - override the current score * @returns {Promise} Promise returning array of Exams to be processed when completed * @memberof PevCalculator */ async getExams(examId?: number): Promise { const exams = this.processResults( await SafePromise.run(() => this.context.examDim .where((i, b) => (b.examId === -1 && i.effStatus === b.effStatus && i.pevStatus === b.pevStatus) || i.id === b.examId, { effStatus: "A", pevStatus: "N", examId: examId || -1 }) .execute() .toPromise() ) ); return exams.toArray(); } /** * Calculate the Exam Statistics for the PEV calculator * * @param {ExamDim} exam * @returns {Promise} Returns the Exam Statistics object generated when scored * @memberof PevCalculator */ async calcExamStats(examDim: ExamDim): Promise { if (examDim == null) { return null; } Logger.log(`Starting initial exam statistics`); var exam = this.processResults(await this.runCalculator(ExamCalculator, examDim)); Logger.log(`Starting question statistics`); var questions = this.processResults(await this.runCalculator(QuestionsCalculator, exam)); Logger.log(`Completing exam statistics`); exam.complete(questions); Logger.log(`Calculating Question PEVs`); questions.forEach(item => item.Pev(exam)); examDim.pevStatus = "C"; examDim.pevMessage = `Last Statistics Calculated ${new Date().toISOString()}`; Logger.log(`Saving results to database`); const results = this.processResults(await SafePromise.run(() => this.context.saveChanges())); return exam; } }