Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Heart Rate Storage #8083

Open
wants to merge 9 commits into
base: dev
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
11 changes: 11 additions & 0 deletions lib/api3/generic/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ function setupGenericCollections (ctx, env, app) {
});
}

if (_.includes(enabledCols, 'heartrate')) {
cols.heartrate = new Collection({
ctx, env, app,
colName: 'heartrate',
storageColName: env.heartrate_colletion || 'heartrate',
fallbackGetDate: fallbackCreatedAt,
dedupFallbackFields: ['created_at'],
fallbackDateField: 'created_at'
});
}

if (_.includes(enabledCols, 'profile')) {
cols.profile = new Collection({
ctx, env, app,
Expand Down
2 changes: 1 addition & 1 deletion lib/api3/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function configure (env, ctx) {
app.set('apiVersion', apiConst.API3_VERSION);
app.set('units', env.DISPLAY_UNITS);
app.set('ci', process.env['CI'] ? true: false);
app.set('enabledCollections', ['devicestatus', 'entries', 'food', 'profile', 'settings', 'treatments']);
app.set('enabledCollections', ['devicestatus', 'entries', 'food', 'heartrate', 'profile', 'settings', 'treatments']);

self.setENVTruthy('API3_SECURITY_ENABLE', apiConst.API3_SECURITY_ENABLE);
self.setENVTruthy('API3_DEDUP_FALLBACK_ENABLED', apiConst.API3_DEDUP_FALLBACK_ENABLED);
Expand Down
3 changes: 2 additions & 1 deletion lib/api3/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"tags": [
{
"name": "generic",
"description": "Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments)"
"description": "Generic operations with each database collection (devicestatus, entries, food, heartrate, profile, settings, treatments)"
},
{
"name": "other",
Expand Down Expand Up @@ -1334,6 +1334,7 @@
"devicestatus",
"entries",
"food",
"heartrate",
"profile",
"settings",
"treatments"
Expand Down
6 changes: 5 additions & 1 deletion lib/api3/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ info:

`food` collection: equal `created_at`

`heartrate` collection: equal `created_at`

`profile` collection: equal `created_at`

`treatments` collection: equal combination of `created_at` and `eventType`

`heartrate` collection: equal `created_at`
</pre>


Expand All @@ -60,7 +64,7 @@ info:

tags:
- name: generic
description: Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments)
description: Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments, heartrate)
- name: other
description: All other various operations

Expand Down
2 changes: 1 addition & 1 deletion lib/data/calcdelta.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module.exports = function calcDelta (oldData, newData) {

function compressArrays(delta, newData) {
// array compression
var compressibleArrays = ['sgvs', 'treatments', 'mbgs', 'cals', 'devicestatus'];
var compressibleArrays = ['sgvs', 'treatments', 'mbgs', 'cals', 'devicestatus', 'heartrate'];
var changesFound = false;

for (var array in compressibleArrays) {
Expand Down
2 changes: 2 additions & 0 deletions lib/server/bootevent.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ function boot (env, language) {
ctx.dataloader = require('../data/dataloader')(env, ctx);
ctx.notifications = require('../notifications')(env, ctx);
ctx.purifier = require('./purifier')(env,ctx);
ctx.heartrate = require('./heartrate')(env, ctx);

if (env.settings.isEnabled('alexa') || env.settings.isEnabled('googlehome')) {
ctx.virtAsstBase = require('../plugins/virtAsstBase')(env, ctx);
Expand Down Expand Up @@ -270,6 +271,7 @@ function boot (env, language) {
ctx.store.ensureIndexes(ctx.profile( ), ctx.profile.indexedFields);
ctx.store.ensureIndexes(ctx.food( ), ctx.food.indexedFields);
ctx.store.ensureIndexes(ctx.activity( ), ctx.activity.indexedFields);
ctx.store.ensureIndexes(ctx.heartrate( ), ctx.heartrate.indexedFields);

next( );
}
Expand Down
1 change: 1 addition & 0 deletions lib/server/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ function setStorage () {
env.devicestatus_collection = readENV('MONGO_DEVICESTATUS_COLLECTION', 'devicestatus');
env.food_collection = readENV('MONGO_FOOD_COLLECTION', 'food');
env.activity_collection = readENV('MONGO_ACTIVITY_COLLECTION', 'activity');
env.heartrate_collection = readENV('MONGO_HEARTRATE_COLLECTION', 'heartrate');

var DB = { url: null, collection: null }
, DB_URL = DB.url ? DB.url : env.storageURI
Expand Down
85 changes: 85 additions & 0 deletions lib/server/heartrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'use strict';

var find_options = require('./query');


function storage (env, ctx) {
var ObjectID = require('mongodb').ObjectID;

function create (obj, fn) {
obj.created_at = (new Date( )).toISOString( );
api().insert(obj, function (err, doc) {
if (err != null && err.message) {
console.log('Heart rate data insertion error', err.message);
fn(err.message, null);
return;
}
fn(null, doc.ops);
});
}

function save (obj, fn) {
obj._id = new ObjectID(obj._id);
obj.created_at = (new Date( )).toISOString( );
api().save(obj, function (err, doc) {
fn(err, doc);
});
}

function query_for (opts) {
return find_options(opts, storage.queryOpts);
}

function list(opts, fn) {
// these functions, find, sort, and limit, are used to
// dynamically configure the request, based on the options we've
// been given

// determine sort options
function sort ( ) {
return opts && opts.sort || {created_at: -1};
}

// configure the limit portion of the current query
function limit ( ) {
if (opts && opts.count) {
return this.limit(parseInt(opts.count));
}
return this;
}

// handle all the results
function toArray (err, entries) {
fn(err, entries);
}

// now just stitch them all together
limit.call(api( )
.find(query_for(opts))
.sort(sort( ))
).toArray(toArray);
}

function remove (_id, fn) {
var objId = new ObjectID(_id);
return api( ).remove({ '_id': objId }, fn);
}

function api ( ) {
return ctx.store.collection(env.heartrate_collection);
}

api.list = list;
api.create = create;
api.query_for = query_for;
api.save = save;
api.remove = remove;
api.indexedFields = ['created_at'];
return api;
}

module.exports = storage;

storage.queryOpts = {
dateField: 'created_at'
};
2 changes: 1 addition & 1 deletion lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ function init () {
}

//TODO: getting sent in status.json, shouldn't be
settings.DEFAULT_FEATURES = ['bgnow', 'delta', 'direction', 'timeago', 'devicestatus', 'upbat', 'errorcodes', 'profile', 'bolus', 'dbsize', 'runtimestate', 'basal', 'careportal'];
settings.DEFAULT_FEATURES = ['bgnow', 'delta', 'direction', 'timeago', 'devicestatus', 'heartrate', 'upbat', 'errorcodes', 'profile', 'bolus', 'dbsize', 'runtimestate', 'basal', 'careportal'];

var wasSet = [];

Expand Down
49 changes: 49 additions & 0 deletions tests/api3.status.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

require('should');

describe('API3 STATUS', function() {
const self = this
, testConst = require('./fixtures/api3/const.json')
, instance = require('./fixtures/api3/instance')
, authSubject = require('./fixtures/api3/authSubject')
;

this.timeout(15000);

before(async () => {
self.instance = await instance.create({});
self.app = self.instance.app;
self.env = self.instance.env;

let authResult = await authSubject(
self.instance.ctx.authorization.storage, ['all'], self.app);

self.subject = authResult.subject;
self.jwt = authResult.jwt;
self.cache = self.instance.cacheMonitor;
});

after(function after () {
self.instance.ctx.bus.teardown();
});

it('GET /status', async () => {
let res = await self.instance
.get(`/api/v3/status`, self.jwt.all)
.expect(200);

const apiConst = require('../lib/api3/const.json')
, software = require('../package.json')
, result = res.body.result;

res.body.status.should.equal(200);
result.version.should.equal(software.version);
result.apiVersion.should.equal(apiConst.API3_VERSION);
result.storage.storage.should.equal("mongodb");
result.srvDate.should.be.within(testConst.YEAR_2019, testConst.YEAR_2050);
result.apiPermissions.devicestatus.should.equal("crud")
result.apiPermissions.heartrate.should.equal("crud")
});
});