Skip to content
This repository has been archived by the owner on Mar 29, 2019. It is now read-only.

delete reference and convert to text #106

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/constants/codes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const ECodes = {
UNDELETABLE_PRIMARY_FIELD: {
code: 'UNDELETABLE_PRIMARY_FIELD',
message: 'Primary field could not be deleted.',
},
UNSUPPORTED_TYPE_CONVERSION: {
code: 'UNSUPPORTED_TYPE_CONVERSION',
message: 'Unsupported type conversion.',
Expand Down
8 changes: 6 additions & 2 deletions app/controllers/fieldValues.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ module.exports = {
return fldValQueries.getValuesByFieldId(fieldId);
},

bulkUpdateToNumber(fieldId, records) {
return fldValQueries.bulkUpdateToNumber(fieldId, records);
bulkUpdate(fieldId, records) {
return fldValQueries.bulkUpdate(fieldId, records);
},

getValuesWithRecords(fieldId, recordIds) {
return fldValQueries.getValuesWithRecords(fieldId, recordIds);
},
};
128 changes: 99 additions & 29 deletions app/controllers/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,48 +75,102 @@ const createReferenceField = async (params, createdField) => {
};

const convertFieldValues = async params => {
//TODO number can not be saved as string in jsonb field
if (params.field.types.name === params.type) {
if (
params.type === 'number' &&
params.field.typeOptions.precision !== params.typeOptions.precision
) {
return await changeToNumber(params);
} else {
return;
}
const fromTypes = params.field.types;
const toTypes = await getByName(params.type);
if (fromTypes.name === toTypes.name) {
return;
} else {
const targetTypes = await getByName(params.type);
if (params.field.types.isPrimitive) {
if (params.type === 'number') {
return await changeToNumber(params);
} else if (targetTypes.isPrimitive) {
return;
}
const values = await fldValController.getValuesByFieldId(params.field.id);
if (!values.length) return;
if (fromTypes.isPrimitive && toTypes.name === 'number') {
return await primeToNumber(params, values);
} else if (fromTypes.name === 'reference' && toTypes.name === 'text') {
return await referenceToText(params, values);
} else if (fromTypes.name === 'multilineText' && toTypes.name === 'text') {
return await multilineTextToText(params, values);
} else if (fromTypes.name === 'text' && toTypes.name === 'multilineText') {
return;
} else if (fromTypes.name === 'number' && toTypes.isPrimitive) {
return await numberToPrime(params, values);
} else {
error(Status.Forbidden, ECodes.UNSUPPORTED_TYPE_CONVERSION, params.type);
}
}
error(Status.Forbidden, ECodes.UNSUPPORTED_TYPE_CONVERSION, params.type);
};

const changeToNumber = async params => {
const numberToPrime = async (params, values) => {
values = values.map(i => {
return {
id: i.id,
value:
i.value !== null
? i.value.toFixed(params.field.typeOptions.precision).toString()
: null,
};
});
return await fldValController.bulkUpdate(params.field.id, values);
};

const multilineTextToText = async (params, values) => {
values = values.map(i => {
return {
id: i.id,
value: i.value !== null ? i.value.replace(/\\n/g, ' ') : null,
};
});
return await fldValController.bulkUpdate(params.field.id, values);
};

const referenceToText = async (params, values) => {
const tblController = require('../controllers/tables');
const primaryFieldId = (await tblController.getPrimaryField(
params.field.typeOptions.referenceTableId,
)).id;
let recordIds = {};
values.forEach(i => {
if (i.value) {
i.value.forEach(j => {
recordIds[j.referenceRowId] = '';
});
}
});
const convertValues = await fldValController.getValuesWithRecords(
primaryFieldId,
Object.keys(recordIds),
);
convertValues.forEach(i => {
recordIds[i.recordId] = i.value;
});
values = values.map(i => {
return {
id: i.id,
value:
i.value !== null
? i.value
.reduce((s, j) => {
return (s += recordIds[j.referenceRowId] + ', ');
}, '')
.slice(0, -1)
: null,
};
});
return await fldValController.bulkUpdate(params.field.id, values);
};

const primeToNumber = async (params, values) => {
checkKeyExists(params, 'typeOptions');
checkKeyExists(params.typeOptions, 'precision');
let values = await fldValController.getValuesByFieldId(params.fieldId);
let precision = parseInt(params.typeOptions.precision);
precision = isNaN(precision) || precision === null ? 1 : precision;
values = values.map(i => {
const _value =
i.value !== null
? parseFloat(i.value.toString().replace(/[^0-9\+.-]/g, '')).toFixed(
precision,
)
? parseFloat(i.value.toString().replace(/[^0-9\+.-]/g, ''))
: null;
return {
id: i.id,
value: isNaN(_value) ? null : _value,
};
});
return await fldValController.bulkUpdateToNumber(params.fieldId, values);
return await fldValController.bulkUpdate(params.field.id, values);
};

module.exports = {
Expand Down Expand Up @@ -170,9 +224,25 @@ module.exports = {
},

async delete(id) {
// TODO handle reference fieldTypes
// TODO can not delete first column
await checkField(id);
const field = await checkField(id);
if (field.fieldPosition && field.fieldPosition.position === 1)
error(Status.Forbidden, ECodes.UNDELETABLE_PRIMARY_FIELD);

if (field.types.name === 'reference') {
const referenceField = await checkField(
field.typeOptions.referenceColumnId,
);
const updatedFields = {
fieldTypeId: await checkType('text'),
typeOptions: null,
};
await fldQueries.update(
updatedFields,
field.typeOptions.referenceColumnId,
);
const _params = { type: 'text', field: referenceField };
await convertFieldValues(_params);
}
await fldQueries.destroy(id);
},

Expand Down
4 changes: 4 additions & 0 deletions app/controllers/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,8 @@ module.exports = {
await posController.bulkCreate(recPosRecords, POSITION_TYPE.RECORD);
return { tableSchemas };
},

getPrimaryField(tableId) {
return tblQueries.getPrimaryField(tableId);
},
};
4 changes: 4 additions & 0 deletions app/models/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ module.exports = (sequelize, DataTypes) => {
foreignKey: 'fieldTypeId',
as: 'types',
});
Fields.hasOne(models.FieldPositions, {
foreignKey: 'siblingId',
as: 'fieldPosition',
});
};
return Fields;
};
23 changes: 18 additions & 5 deletions app/queries/fieldValues.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,27 @@ module.exports = {
});
},

bulkUpdateToNumber(fieldId, records) {
bulkUpdate(fieldId, records) {
let sql = `update "FieldValues" set "value" = case`;
let values = [];
records.forEach(i => {
sql += ` when "id" = ${i.id} then ?`;
values.push(i.value);
let value = null;
if (i.value !== null) {
if (typeof i.value === 'string') {
value = `'"${i.value}"'`;
} else {
value = `'${i.value}'`;
}
}
sql += ` when "id" = ${i.id} then ${value}`;
});
sql += ` else "value" end where "fieldId" = '${fieldId}'`;
return sequelize.query(sql, { replacements: values });
return sequelize.query(sql);
},

getValuesWithRecords(fieldId, recordIds) {
return FieldValues.findAll({
attributes: ['fieldId', 'recordId', 'value'],
where: { fieldId, recordId: { $in: recordIds } },
});
},
};
7 changes: 6 additions & 1 deletion app/queries/fields.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { sequelize, Fields, FieldTypes } = require('../models');
const { sequelize, Fields, FieldTypes, FieldPositions } = require('../models');

module.exports = {
create(params) {
Expand All @@ -15,6 +15,11 @@ module.exports = {
as: 'types',
attributes: { exclude: ['updatedAt', 'createdAt'] },
},
{
model: FieldPositions,
as: 'fieldPosition',
attributes: ['position'],
},
],
});
},
Expand Down
19 changes: 19 additions & 0 deletions app/queries/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,23 @@ module.exports = {
bulkCreate(records) {
return Tables.bulkCreate(records);
},

getPrimaryField(tableId) {
return FieldPositions.findOne({
attributes: [
[sequelize.col('field.name'), 'fieldName'],
[sequelize.col('field.id'), 'id'],
],
where: { parentId: tableId },
include: [
{
attributes: [],
model: Fields,
as: 'field',
},
],
order: [['position', 'asc']],
limit: 1,
});
},
};