nightscout
Version:
Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.
178 lines (135 loc) • 4.41 kB
JavaScript
'use strict';
const _ = require('lodash')
, checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$")
, ObjectID = require('mongodb').ObjectID
;
/**
* Normalize document (make it mongoDB independent)
* @param {Object} doc - document loaded from mongoDB
*/
function normalizeDoc (doc) {
if (!doc.identifier) {
doc.identifier = doc._id.toString();
}
delete doc._id;
}
/**
* Parse filter definition array into mongoDB filtering object
* @param {any} filterDef
* @param {string} logicalOperator
* @param {bool} onlyValid
*/
function parseFilter (filterDef, logicalOperator, onlyValid) {
let filter = { };
if (!filterDef)
return filter;
if (!_.isArray(filterDef)) {
return filterDef;
}
let clauses = [];
for (const itemDef of filterDef) {
let item;
switch (itemDef.operator) {
case 'eq':
item = itemDef.value;
break;
case 'ne':
item = { $ne: itemDef.value };
break;
case 'gt':
item = { $gt: itemDef.value };
break;
case 'gte':
item = { $gte: itemDef.value };
break;
case 'lt':
item = { $lt: itemDef.value };
break;
case 'lte':
item = { $lte: itemDef.value };
break;
case 'in':
item = { $in: itemDef.value.toString().split('|') };
break;
case 'nin':
item = { $nin: itemDef.value.toString().split('|') };
break;
case 're':
item = { $regex: itemDef.value.toString() };
break;
default:
throw new Error('Unsupported or missing filter operator ' + itemDef.operator);
}
if (logicalOperator === 'or') {
let clause = { };
clause[itemDef.field] = item;
clauses.push(clause);
}
else {
filter[itemDef.field] = item;
}
}
if (logicalOperator === 'or') {
filter = { $or: clauses };
}
if (onlyValid) {
filter.isValid = { $ne: false };
}
return filter;
}
/**
* Create query filter for single document with identifier fallback
* @param {string} identifier
*/
function filterForOne (identifier) {
const filterOpts = [ { identifier } ];
// fallback to "identifier = _id"
if (checkForHexRegExp.test(identifier)) {
filterOpts.push({ _id: ObjectID(identifier) });
}
return { $or: filterOpts };
}
/**
* Create query filter to check whether the document already exists in the storage.
* This function resolves eventual fallback deduplication.
* @param {string} identifier - identifier of document to check its existence in the storage
* @param {Object} doc - document to check its existence in the storage
* @param {Array} dedupFallbackFields - fields that all need to be matched to identify document via fallback deduplication
* @returns {Object} - query filter for mongo or null in case of no identifying possibility
*/
function identifyingFilter (identifier, doc, dedupFallbackFields) {
const filterItems = [];
if (identifier) {
// standard identifier field (APIv3)
filterItems.push({ identifier: identifier });
// fallback to "identifier = _id" (APIv1)
if (checkForHexRegExp.test(identifier)) {
filterItems.push({ identifier: { $exists: false }, _id: ObjectID(identifier) });
}
}
// let's deal with eventual fallback deduplication
if (!_.isEmpty(doc) && _.isArray(dedupFallbackFields) && dedupFallbackFields.length > 0) {
let dedupFilterItems = [];
_.each(dedupFallbackFields, function addDedupField (field) {
if (doc[field] !== undefined) {
let dedupFilterItem = { };
dedupFilterItem[field] = doc[field];
dedupFilterItems.push(dedupFilterItem);
}
});
if (dedupFilterItems.length === dedupFallbackFields.length) { // all dedup fields are present
dedupFilterItems.push({ identifier: { $exists: false } }); // force not existing identifier for fallback deduplication
filterItems.push({ $and: dedupFilterItems });
}
}
if (filterItems.length > 0)
return { $or: filterItems };
else
return null; // we don't have any filtering rule to identify the document in the storage
}
module.exports = {
normalizeDoc,
parseFilter,
filterForOne,
identifyingFilter
};