Files
cgm-remote-monitor/lib/data/dataloader.js
T
Sulka HaroandGitHub 8f25a6e7a4 Fix all issues from ESLint (#4730)
* Cherry picks the ES language changes from #4690

* Fix small issues found in linting

* * Fix all but one eslint complaint in the bundled code
* Add eslint and js-beautify rc files into the repo
2019-07-17 15:04:57 +03:00

405 lines
11 KiB
JavaScript

'use strict';
var _ = require('lodash');
var async = require('async');
var times = require('../times');
var fitTreatmentsToBGCurve = require('./treatmenttocurve');
var ONE_DAY = 86400000,
TWO_DAYS = 172800000;
function uniq(a) {
var seen = {};
return a.filter(function(item) {
// eslint-disable-next-line no-prototype-builtins
return seen.hasOwnProperty(item.mills) ? false : (seen[item.mills] = true);
});
}
function init(env, ctx) {
var dataloader = {};
dataloader.update = function update(ddata, opts, done) {
//console.log("Database is connected: " + ctx.store.client.isConnected());
if (opts && done == null && opts.call) {
done = opts;
opts = {
lastUpdated: Date.now(),
frame: false
};
}
if (opts.frame) {
ddata.page = {
frame: true,
after: opts.lastUpdated
// , before: opts.
};
}
ddata.lastUpdated = opts.lastUpdated;
// console.log('LOOKING SINCE', (new Date(ddata.lastUpdated)));
function loadComplete(err, result) {
ddata.treatments = _.uniq(ddata.treatments, false, function(item) {
return item._id.toString();
});
//sort treatments so the last is the most recent
ddata.treatments = _.sortBy(ddata.treatments, function(item) {
return item.mills;
});
fitTreatmentsToBGCurve(ddata, env, ctx);
if (err) {
console.error(err);
}
ddata.processTreatments(true);
var counts = [];
_.forIn(ddata, function each(value, key) {
if (_.isArray(value) && value.length > 0) {
counts.push(key + ':' + value.length);
}
});
console.info('Load Complete:\n\t', counts.join(', '));
done(err, result);
}
// clear treatments, we're going to merge from more queries
ddata.treatments = [];
async.parallel([
loadEntries.bind(null, ddata, ctx)
, loadTreatments.bind(null, ddata, ctx)
, loadProfileSwitchTreatments.bind(null, ddata, ctx)
, loadSensorAndInsulinTreatments.bind(null, ddata, ctx)
, loadProfile.bind(null, ddata, ctx)
, loadFood.bind(null, ddata, ctx)
, loadDeviceStatus.bind(null, ddata, env, ctx)
, loadActivity.bind(null, ddata, ctx)
], loadComplete);
};
return dataloader;
}
function loadEntries(ddata, ctx, callback) {
var dateRange = {
$gte: ddata.lastUpdated - TWO_DAYS
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = ddata.lastUpdated;
}
var q = {
find: {
date: dateRange
},
sort: {
date: 1
}
};
ctx.entries.list(q, function(err, results) {
if (err) {
console.log("Problem loading entries");
}
if (!err && results) {
var mbgs = [];
var sgvs = [];
var cals = [];
results.forEach(function(element) {
if (element) {
if (element.mbg) {
mbgs.push({
mgdl: Number(element.mbg),
mills: element.date,
device: element.device
});
} else if (element.sgv) {
sgvs.push({
mgdl: Number(element.sgv),
mills: element.date,
device: element.device,
direction: element.direction,
filtered: element.filtered,
unfiltered: element.unfiltered,
noise: element.noise,
rssi: element.rssi
});
} else if (element.type === 'cal') {
cals.push({
mills: element.date,
scale: element.scale,
intercept: element.intercept,
slope: element.slope
});
}
}
});
//stop using uniq for SGVs since we use buckets, also enables more detailed monitoring
ddata.sgvs = sgvs;
ddata.mbgs = uniq(mbgs);
ddata.cals = uniq(cals);
}
callback();
});
}
function mergeToTreatments(ddata, results) {
var filtered = _.filter(results, function hasId(treatment) {
return !_.isEmpty(treatment._id);
});
var treatments = _.map(filtered, function update(treatment) {
treatment.mills = new Date(treatment.created_at).getTime();
return treatment;
});
//filter out temps older than a day and an hour ago since we don't display them
var oldestAgo = ddata.lastUpdated - TWO_DAYS - times.hour().msecs;
treatments = _.filter(treatments, function noOldTemps(treatment) {
return !treatment.eventType || treatment.eventType.indexOf('Temp Basal') === -1 || treatment.mills > oldestAgo;
});
ddata.treatments = _.unionWith(ddata.treatments, treatments, function(a, b) {
return a._id.toString() == b._id.toString();
});
}
function loadActivity(ddata, ctx, callback) {
var dateRange = {
$gte: new Date(ddata.lastUpdated - (ONE_DAY * 2)).toISOString()
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = new Date(ddata.lastUpdated).toISOString();
}
var q = {
find: {
created_at: dateRange
},
sort: {
created_at: 1
}
};
var activity = [];
ctx.activity.list(q, function(err, results) {
if (err) {
console.log("Problem loading activity data");
}
if (!err && results) {
var activity = [];
results.forEach(function(element) {
if (element) {
if (element.created_at) {
var d = new Date(element.created_at);
activity.push({
mills: d,
heartrate: element.heartrate,
steps: element.steps,
activitylevel: element.activitylevel
});
}
}
});
ddata.activity = uniq(activity);
}
callback();
});
}
function loadTreatments(ddata, ctx, callback) {
// Load 2.5 days to cover last 48 hours including overlapping temp boluses or temp targets
var dateRange = {
$gte: new Date(ddata.lastUpdated - (ONE_DAY * 2.5)).toISOString()
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = new Date(ddata.lastUpdated).toISOString();
}
var tq = {
find: {
created_at: dateRange
},
sort: {
created_at: 1
}
};
ctx.treatments.list(tq, function(err, results) {
if (!err && results) {
mergeToTreatments(ddata, results);
}
callback();
});
}
function loadProfileSwitchTreatments(ddata, ctx, callback) {
var dateRange = {
$gte: new Date(ddata.lastUpdated - (ONE_DAY * 31 * 12)).toISOString()
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = new Date(ddata.lastUpdated).toISOString();
}
// Load the latest profile switch treatment
var tq = {
find: {
eventType: 'Profile Switch',
created_at: dateRange,
duration: 0
},
sort: {
created_at: -1
},
count: 1
};
ctx.treatments.list(tq, function(err, results) {
if (!err && results) {
mergeToTreatments(ddata, results);
}
// Store last profile switch
if (results) {
ddata.lastProfileFromSwitch = null;
var now = new Date().getTime();
for (var p = 0; p < results.length; p++) {
var pdate = new Date(results[p].created_at).getTime();
if (pdate < now) {
ddata.lastProfileFromSwitch = results[p].profile;
break;
}
}
}
callback();
});
}
function loadSensorAndInsulinTreatments(ddata, ctx, callback) {
async.parallel([
loadLatestSingle.bind(null, ddata, ctx, 'Sensor Start')
,loadLatestSingle.bind(null, ddata, ctx, 'Sensor Change')
,loadLatestSingle.bind(null, ddata, ctx, 'Site Change')
,loadLatestSingle.bind(null, ddata, ctx, 'Insulin Change')
,loadLatestSingle.bind(null, ddata, ctx, 'Pump Battery Change')
], callback);
}
function loadLatestSingle(ddata, ctx, dataType, callback) {
var dateRange = {
$gte: new Date(ddata.lastUpdated - (ONE_DAY * 32)).toISOString()
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = new Date(ddata.lastUpdated).toISOString();
}
var tq = {
find: {
eventType: {
$eq: dataType
},
created_at: dateRange
},
sort: {
created_at: -1
},
count: 1
};
ctx.treatments.list(tq, function(err, results) {
if (!err && results) {
mergeToTreatments(ddata, results);
}
callback();
});
}
function loadProfile(ddata, ctx, callback) {
ctx.profile.last(function(err, results) {
if (!err && results) {
var profiles = [];
results.forEach(function(element) {
if (element) {
profiles[0] = element;
}
});
ddata.profiles = profiles;
}
callback();
});
}
function loadFood(ddata, ctx, callback) {
ctx.food.list(function(err, results) {
if (!err && results) {
ddata.food = results;
}
callback();
});
}
function loadDeviceStatus(ddata, env, ctx, callback) {
var dateRange = {
$gte: new Date(ddata.lastUpdated - ONE_DAY).toISOString()
};
if (ddata.page && ddata.page.frame) {
dateRange['$lte'] = new Date(ddata.lastUpdated).toISOString();
}
var opts = {
find: {
created_at: dateRange
},
sort: {
created_at: -1
}
};
if (env.extendedSettings.devicestatus && env.extendedSettings.devicestatus.advanced) {
//not adding count: 1 restriction
} else {
opts.count = 1;
}
ctx.devicestatus.list(opts, function(err, results) {
if (!err && results) {
ddata.devicestatus = _.map(results, function eachStatus(result) {
result.mills = new Date(result.created_at).getTime();
if ('uploaderBattery' in result) {
result.uploader = {
battery: result.uploaderBattery
};
delete result.uploaderBattery;
}
return result;
}).reverse();
} else {
ddata.devicestatus = [];
}
callback();
});
}
module.exports = init;