Skip to content

Commit

Permalink
#276 JSON attributes as attachments (#285)
Browse files Browse the repository at this point in the history
Following changes intend to tackle performance problems in the backend.
Main idea is avoid passing JSON attributes all around whenever uploading
LabRecordImports or ElectronicPharmacyStockRecords. Instead of doing that, 
JSON parameters are now received as files and loaded by the workers
only when it's required. These files are related with the model instances
through `has_one_attached` macro.

This commit introduces breaking changes regarding client server interaction, 
and every Collector using this version should point to a server 
that includes these changes.
  • Loading branch information
lmatayoshi authored May 6, 2020
1 parent edb9c64 commit ca986d7
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 14 deletions.
15 changes: 11 additions & 4 deletions app/actions/electronicPharmacyStockRecords.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import snakeCaseKeys from 'snakecase-keys';
import { isObject } from 'lodash';
import { fetchAuthenticated } from '../utils/fetch';
import { fetchEntity, fetchEntitySingular } from './fetch';
import createJSONFile from '../utils/attachments';
import db from '../db';

const FETCH_ELECTRONIC_PHARMACY_STOCK_RECORDS =
Expand All @@ -14,12 +15,14 @@ const FETCHED_ELECTRONIC_PHARMACY_STOCK_RECORDS =
const FETCHED_ELECTRONIC_PHARMACY_STOCK_RECORD =
'FETCHED_ELECTRONIC_PHARMACY_STOCK_RECORD';

const uploadMapper = async (attr, record) =>
snakeCaseKeys({
...attr,
const uploadMapper = async (attr, record) => {
const { rows, ...withoutRows } = attr;
return snakeCaseKeys({
...withoutRows,
date: Object.values(attr.date),
siteId: await record.getRemoteSiteId()
});
};

export const fetchElectronicPharmacyStockRecords = fetchEntity(
'ElectronicPharmacyStockRecord'
Expand Down Expand Up @@ -50,10 +53,13 @@ export const uploadNewElectronicPharmacyStockRecords = () => async (
const body = new FormData();
const contents = fs.readFileSync(electronicPharmacyStockRecord.filePath);
const blob = new Blob([contents]);
const electronicPharmacyValues = electronicPharmacyStockRecord.dataValues;
const mapper = await uploadMapper(
electronicPharmacyStockRecord.dataValues,
electronicPharmacyValues,
electronicPharmacyStockRecord
);
const rowsFile = createJSONFile(electronicPharmacyValues.rows, 'rows.json');

// eslint-disable-next-line
Object.keys(mapper).forEach(key => {
if (isObject(mapper[key])) {
Expand All @@ -63,6 +69,7 @@ export const uploadNewElectronicPharmacyStockRecords = () => async (
}
});
body.append('sheet_file', blob);
body.append('rows_file', rowsFile);
fetchAuthenticated('/api/v1/electronic_pharmacy_stock_records', user.auth, {
method: 'POST',
body,
Expand Down
35 changes: 25 additions & 10 deletions app/actions/labRecords.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isObject } from 'lodash';
import db from '../db';

import { fetchAuthenticated } from '../utils/fetch';
import createJSONFile from '../utils/attachments';
import { fetchEntity } from './fetch';

const FETCH_LAB_RECORDS = 'FETCH_LAB_RECORDS';
Expand All @@ -12,16 +13,14 @@ const FETCH_LAB_RECORDS_FAILED = 'FETCH_LAB_RECORDS_FAILED';
const FETCHED_LAB_RECORD = 'FETCHED_LAB_RECORD';
const FETCHING_LAB_RECORD = 'FETCHING_LAB_RECORD';

const uploadMapper = async (attr, record) =>
snakeCaseKeys({
...attr,
const uploadMapper = async (attr, record) => {
const { rows, ...withoutRows } = attr;
return snakeCaseKeys({
...withoutRows,
date: Object.values(attr.date),
siteId: await record.getRemoteSiteId(),
lab_records_attributes: attr.rows.map((row, index) => ({
content: [...row],
row: index
}))
siteId: await record.getRemoteSiteId()
});
};

export const syncLabRecords = () => async dispatch =>
dispatch(uploadNewLabRecords()).then(() =>
Expand All @@ -41,7 +40,18 @@ export const uploadNewLabRecords = () => async (dispatch, getState) => {
const body = new FormData();
const contents = fs.readFileSync(labRecord.filePath);
const blob = new Blob([contents]);
const mapper = await uploadMapper(labRecord.dataValues, labRecord);
const labRecordValues = labRecord.dataValues;
const mapper = await uploadMapper(labRecordValues, labRecord);
const labRecordAttributes = labRecordValues.rows.map((row, index) => ({
content: [...row],
row: index
}));
const labRecordAttributesFile = createJSONFile(
labRecordAttributes,
'lab_records_attributes.json'
);
const rowsFile = createJSONFile(labRecordValues.rows, 'rows.json');

// eslint-disable-next-line
Object.keys(mapper).forEach(key => {
if (isObject(mapper[key])) {
Expand All @@ -51,6 +61,8 @@ export const uploadNewLabRecords = () => async (dispatch, getState) => {
}
});
body.append('sheet_file', blob);
body.append('lab_records_attributes_file', labRecordAttributesFile);
body.append('rows_file', rowsFile);
fetchAuthenticated('/api/v1/lab_record_imports', user.auth, {
method: 'POST',
body,
Expand Down Expand Up @@ -84,12 +96,15 @@ export const uploadUpdatedLabRecords = () => async (dispatch, getState) => {
});

collectionToUpdate.forEach(async labRecord => {
const body = new FormData();
body.append('rows_file', createJSONFile(labRecord.rows, 'rows.json'));
fetchAuthenticated(
`/api/v1/lab_record_imports/${labRecord.remoteId}`,
user.auth,
{
method: 'PUT',
body: { rows: labRecord.rows }
body,
contentType: null
}
)
.then(() => {
Expand Down
8 changes: 8 additions & 0 deletions app/utils/attachments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const createJSONFile = (content, filename) => {
const blob = new Blob([JSON.stringify(content)], {
type: 'application/json'
});
return new File([blob], filename);
};

export default createJSONFile;

0 comments on commit ca986d7

Please sign in to comment.