packages/optimise-core/src/controllers/dataController.js
import moment from 'moment';
import DataCore from '../core/data';
import ErrorHelper from '../utils/error_helper';
import message from '../utils/message-utils';
import formatToJSON from '../utils/format-response';
import { getEntry, createEntry, updateEntry } from '../utils/controller-utils';
const optionsContainer = {
visit: {
entryIdString: 'visitId',
fieldTable: 'AVAILABLE_FIELDS_VISITS',
entryTable: 'VISITS',
errMsgForUnfoundEntry: message.dataMessage.VISIT,
dataTable: 'VISIT_DATA',
dataTableForeignKey: 'visit'
},
clinicalEvent: {
entryIdString: 'clinicalEventId',
fieldTable: 'AVAILABLE_FIELDS_CE',
entryTable: 'CLINICAL_EVENTS',
errMsgForUnfoundEntry: message.dataMessage.CLINICALEVENT,
dataTable: 'CLINICAL_EVENTS_DATA',
dataTableForeignKey: 'clinicalEvent'
},
test: {
entryIdString: 'testId',
fieldTable: 'AVAILABLE_FIELDS_TESTS',
entryTable: 'ORDERED_TESTS',
errMsgForUnfoundEntry: message.dataMessage.TEST,
dataTable: 'TEST_DATA',
dataTableForeignKey: 'test'
},
pregnancyEntry: {
entryIdString: 'pregnancyEntryId',
fieldTable: 'AVAILABLE_FIELDS_PREGNANCY_ENTRY',
entryTable: 'PREGNANCY_ENTRY',
errMsgForUnfoundEntry: message.dataMessage.PREGNANCYENTRY,
dataTable: 'PREGNANCY_ENTRY_DATA',
dataTableForeignKey: 'pregnancyEntry'
}
};
class DataController {
static _RouterDeleteData({ params, body, user }, res) {
const options = optionsContainer[`${params.dataType}`];
if (options === undefined) {
res.status(400).json(ErrorHelper(`data type ${params.dataType} not supported.`));
return;
}
if (!body.hasOwnProperty(`${params.dataType}Id`) || !body.hasOwnProperty('delete')) {
res.status(400).json(ErrorHelper(message.userError.MISSINGARGUMENT));
return;
}
DataCore.deleteData(user, options, body[`${params.dataType}Id`], body.delete)
.then((result) => {
res.status(200).json(formatToJSON(result));
return true;
}).catch((error) => {
res.status(400).json(ErrorHelper(message.errorMessages.DELETEFAIL, error));
return false;
});
}
static _getField(table, id) {
return getEntry(table, { id }, { id: 'id', definition: 'definition', type: 'type', permittedValues: 'permittedValues', referenceType: 'referenceType' });
}
static _checkField({ fieldTable }, entries) {
const promiseArr = [];
for (let i = 0; entries.hasOwnProperty('updates') && i < entries.updates.length; i++) {
promiseArr.push(DataController._getField(fieldTable, entries.updates[i].field));
}
for (let i = 0; entries.hasOwnProperty('adds') && i < entries.adds.length; i++) {
promiseArr.push(DataController._getField(fieldTable, entries.adds[i].field));
}
return Promise.all(promiseArr);
}
static _formatEntries({ dataTableForeignKey, entryIdString }, { body, user }) {
const returned = {};
const numOfUpdates = (body.hasOwnProperty('update')) ? Object.keys(body.update).length : 0;
const numOfAdds = (body.hasOwnProperty('add')) ? Object.keys(body.add).length : 0;
const updates = [];
const adds = [];
for (let i = 0; i < numOfUpdates; i++) {
const entry = {
field: Object.keys(body.update)[i],
value: body.update[Object.keys(body.update)[i]],
createdByUser: user.id,
deleted: '-'
};
entry[dataTableForeignKey] = body[entryIdString];
updates.push(entry);
}
for (let i = 0; i < numOfAdds; i++) {
const entry = {
field: Object.keys(body.add)[i],
value: body.add[Object.keys(body.add)[i]],
createdByUser: user.id,
deleted: '-'
};
entry[dataTableForeignKey] = body[entryIdString];
adds.push(entry);
}
if (numOfAdds > 0)
returned.adds = adds;
if (numOfUpdates > 0)
returned.updates = updates;
return returned;
}
static _createAndUpdate({ user }, { dataTableForeignKey, dataTable }, inputData) {
const promiseArr = [];
for (let i = 0; inputData.hasOwnProperty('updates') && i < inputData.updates.length; i++) {
const whereObj = {};
whereObj[dataTableForeignKey] = inputData.entryId;
whereObj.field = inputData.updates[i].field;
promiseArr.push(updateEntry(dataTable, user, '*', whereObj, inputData.updates[i]));
}
for (let i = 0; inputData.hasOwnProperty('adds') && i < inputData.adds.length; i++) {
promiseArr.push(createEntry(dataTable, inputData.adds[i]));
}
return Promise.all(promiseArr);
}
static _RouterAddOrUpdate(req, res) {
if (optionsContainer.hasOwnProperty(`${req.params.dataType}`)) {
const options = optionsContainer[req.params.dataType];
if (!(req.body.hasOwnProperty(`${options.entryIdString}`) &&
(req.body.hasOwnProperty('add') || req.body.hasOwnProperty('update')))) {
res.status(400).json(ErrorHelper(message.dataMessage.MISSINGVALUE + options.entryIdString));
return;
} else {
const entries = DataController._formatEntries(options, req);
entries.entryId = req.body[options.entryIdString];
if (!req.body.hasOwnProperty('update')) { req.body.update = {}; } //adding an empty obj so that the code later doesn't throw error for undefined
if (!req.body.hasOwnProperty('add')) { req.body.add = {}; } //same
// Verify that the entryTable ID exists in database (i.e. visitId:1 in body must have the row with id 1 in VISIT Table)
return getEntry(options.entryTable, { id: req.body[options.entryIdString], deleted: '-' }, '*')
.then((entryResult) => {
if (entryResult.length !== 1) {
res.status(404).json(ErrorHelper(options.errMsgForUnfoundEntry));
return;
}
const entryType = entryResult[0].type;
return DataController._checkField(options, entries).then((result) => {
if (result.length <= 0) {
res.status(400).json(ErrorHelper(message.dataMessage.FIELDNOTFOUND));
return false;
}
for (let i = 0; i < result.length; i++) {
if (result[i].length !== 1) {
res.status(400).json(ErrorHelper(message.dataMessage.FIELDNOTFOUND));
return false;
}
if (result[i][0].referenceType !== entryType) {
res.status(400).json(ErrorHelper(message.dataMessage.INVALIDFIELD));
return false;
}
if (result[i].length === 1) {
const addOrUpdate = (entries.hasOwnProperty('updates') && i < entries.updates.length) ? 'update' : 'add';
const fieldId = result[i][0].id;
const fieldDefinition = result[i][0].definition;
const fieldType = result[i][0].type;
const inputValue = req.body[addOrUpdate][fieldId];
let time;
switch (fieldType) {
case 5: //'B':
if (inputValue !== '' && !(inputValue === true || inputValue === false || inputValue === 1 || inputValue === 0 || inputValue === '1' || inputValue === '0' || inputValue.toUpperCase() === 'YES' || inputValue.toUpperCase() === 'NO')) {
res.status(400).json(ErrorHelper(`${message.dataMessage.BOOLEANFIELD}${fieldDefinition}`));
return false;
}
break;
case 3: //'C':
if (inputValue !== '' && inputValue !== 'unselected' && result[i][0]['permittedValues'] !== null && !(result[i][0]['permittedValues'].split(',').includes(inputValue))) { //see if the value is in the permitted values
res.status(400).json(ErrorHelper(`${fieldDefinition}${message.dataMessage.CHARFIELD}${result[i][0]['permittedValues']}`));
return false;
}
break;
case 1: //'I':
if (inputValue !== '' && !(parseInt(inputValue) === parseFloat(inputValue))) {
res.status(400).json(ErrorHelper(`${message.dataMessage.INTEGERFIELD}${fieldDefinition}`));
return false;
}
break;
case 2: //'F':
if (inputValue !== '' && !(parseFloat(inputValue).toString() === inputValue.toString())) {
res.status(400).json(ErrorHelper(`${message.dataMessage.NUMBERFIELD}${fieldDefinition}`));
return false;
}
break;
case 6: //'D':
time = moment(inputValue, moment.ISO_8601);
if (inputValue !== '' && !time.isValid()) {
const msg = (time.invalidAt() === undefined || time.invalidAt() < 0) ? message.userError.INVALIDDATE : message.dateError[time.invalidAt()];
res.status(400).json(ErrorHelper(`${msg} at field ${fieldDefinition}`));
return false;
}
break;
}
}
}
return DataController._createAndUpdate(req, options, entries).then(() => {
res.status(200).json(formatToJSON(`${message.dataMessage.SUCCESS}`));
return true;
}).catch((error) => {
res.status(400).json(ErrorHelper(message.dataMessage.ERROR, error));
return false;
});
}).catch((error) => {
res.status(400).json(ErrorHelper(message.dataMessage.FIELDNOTFOUND, error));
return false;
});
}).catch((error) => {
res.status(404).json(ErrorHelper(options.errMsgForUnfoundEntry, error));
return false;
});
}
} else {
res.status(404).json(ErrorHelper(message.userError.WRONGPATH));
}
}
}
export default DataController;