@phema/cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
300 lines (231 loc) • 9.42 kB
JavaScript
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
var _require = require('../datatypes/uncertainty'),
Uncertainty = _require.Uncertainty;
function areNumbers(a, b) {
return typeof a === 'number' && typeof b === 'number';
}
function areStrings(a, b) {
return typeof a === 'string' && typeof b === 'string';
}
function areDateTimesOrQuantities(a, b) {
return a && a.isDateTime && b && b.isDateTime || a && a.isDate && b && b.isDate || a && a.isQuantity && b && b.isQuantity;
}
function isUncertainty(x) {
return x instanceof Uncertainty;
}
function lessThan(a, b, precision) {
if (areNumbers(a, b) || areStrings(a, b)) {
return a < b;
} else if (areDateTimesOrQuantities(a, b)) {
return a.before(b, precision);
} else if (isUncertainty(a)) {
return a.lessThan(b);
} else if (isUncertainty(b)) {
return Uncertainty.from(a).lessThan(b);
} else {
return null;
}
}
function lessThanOrEquals(a, b, precision) {
if (areNumbers(a, b) || areStrings(a, b)) {
return a <= b;
} else if (areDateTimesOrQuantities(a, b)) {
return a.sameOrBefore(b, precision);
} else if (isUncertainty(a)) {
return a.lessThanOrEquals(b);
} else if (isUncertainty(b)) {
return Uncertainty.from(a).lessThanOrEquals(b);
} else {
return null;
}
}
function greaterThan(a, b, precision) {
if (areNumbers(a, b) || areStrings(a, b)) {
return a > b;
} else if (areDateTimesOrQuantities(a, b)) {
return a.after(b, precision);
} else if (isUncertainty(a)) {
return a.greaterThan(b);
} else if (isUncertainty(b)) {
return Uncertainty.from(a).greaterThan(b);
} else {
return null;
}
}
function greaterThanOrEquals(a, b, precision) {
if (areNumbers(a, b) || areStrings(a, b)) {
return a >= b;
} else if (areDateTimesOrQuantities(a, b)) {
return a.sameOrAfter(b, precision);
} else if (isUncertainty(a)) {
return a.greaterThanOrEquals(b);
} else if (isUncertainty(b)) {
return Uncertainty.from(a).greaterThanOrEquals(b);
} else {
return null;
}
}
function equivalent(a, b) {
if (a == null && b == null) {
return true;
}
if (a == null || b == null) {
return false;
}
if (isCode(a)) {
return codesAreEquivalent(a, b);
} // Quantity equivalence is the same as Quantity equality
if (a.isQuantity) {
return a.equals(b);
} // Use overloaded 'equivalent' function if it is available
if (typeof a.equivalent === 'function') {
return a.equivalent(b);
}
var _getClassOfObjects = getClassOfObjects(a, b),
_getClassOfObjects2 = _slicedToArray(_getClassOfObjects, 2),
aClass = _getClassOfObjects2[0],
bClass = _getClassOfObjects2[1];
switch (aClass) {
case '[object Array]':
return compareEveryItemInArrays(a, b, equivalent);
case '[object Object]':
return compareObjects(a, b, equivalent);
case '[object String]':
// Make sure b is also a string
if (bClass === '[object String]') {
// String equivalence is case- and locale insensitive
a = a.replace(/\s/g, ' ');
b = b.replace(/\s/g, ' ');
return a.localeCompare(b, 'en', {
sensitivity: 'base'
}) === 0;
}
break;
}
return equals(a, b);
}
function isCode(object) {
return object.hasMatch && typeof object.hasMatch === 'function';
}
function codesAreEquivalent(code1, code2) {
return code1.hasMatch(code2);
}
function getClassOfObjects(object1, object2) {
return [object1, object2].map(function (obj) {
return {}.toString.call(obj);
});
}
function compareEveryItemInArrays(array1, array2, comparisonFunction) {
return array1.length === array2.length && array1.every(function (item, i) {
return comparisonFunction(item, array2[i]);
});
}
function compareObjects(a, b, comparisonFunction) {
if (!classesEqual(a, b)) {
return false;
}
return deepCompareKeysAndValues(a, b, comparisonFunction);
}
function classesEqual(object1, object2) {
return object2 instanceof object1.constructor && object1 instanceof object2.constructor;
}
function deepCompareKeysAndValues(a, b, comparisonFunction) {
var finalComparisonResult;
var aKeys = getKeysFromObject(a).sort();
var bKeys = getKeysFromObject(b).sort(); // Array.every() will only return true or false, so set a flag for if we should return null
var shouldReturnNull = false; // Check if both arrays of keys are the same length and key names match
if (aKeys.length === bKeys.length && aKeys.every(function (value, index) {
return value === bKeys[index];
})) {
finalComparisonResult = aKeys.every(function (key) {
// if both are null we should return true to satisfy ignoring empty values in tuples
if (a[key] == null && b[key] == null) {
return true;
}
var comparisonResult = comparisonFunction(a[key], b[key]);
if (comparisonResult === null) {
shouldReturnNull = true;
}
return comparisonResult;
});
} else {
finalComparisonResult = false;
}
if (shouldReturnNull) {
return null;
}
return finalComparisonResult;
}
function getKeysFromObject(object) {
return Object.keys(object).filter(function (k) {
return !isFunction(object[k]);
});
}
function isFunction(input) {
return input instanceof Function || {}.toString.call(input) === '[object Function]';
}
function equals(a, b) {
// Handle null cases first: spec says if either is null, return null
if (a == null || b == null) {
return null;
} // If one is a Quantity, use the Quantity equals function
if (a && a.isQuantity) {
return a.equals(b);
} // If one is a Ratio, use the ratio equals function
if (a && a.isRatio) {
return a.equals(b);
} // If one is an Uncertainty, convert the other to an Uncertainty
if (a instanceof Uncertainty) {
b = Uncertainty.from(b);
} else if (b instanceof Uncertainty) {
a = Uncertainty.from(a);
} // Use overloaded 'equals' function if it is available
if (typeof a.equals === 'function') {
return a.equals(b);
} // Return true of the objects are primitives and are strictly equal
if (_typeof(a) === _typeof(b) && typeof a === 'string' || typeof a === 'number' || typeof a === 'boolean') {
return a === b;
} // Return false if they are instances of different classes
var _getClassOfObjects3 = getClassOfObjects(a, b),
_getClassOfObjects4 = _slicedToArray(_getClassOfObjects3, 2),
aClass = _getClassOfObjects4[0],
bClass = _getClassOfObjects4[1];
if (aClass !== bClass) {
return false;
}
switch (aClass) {
case '[object Date]':
// Compare the ms since epoch
return a.getTime() === b.getTime();
case '[object RegExp]':
// Compare the components of the regular expression
return ['source', 'global', 'ignoreCase', 'multiline'].every(function (p) {
return a[p] === b[p];
});
case '[object Array]':
if (a.indexOf(null) >= 0 || a.indexOf(undefined) >= 0 || b.indexOf(null) >= 0 || b.indexOf(undefined) >= 0) {
return null;
}
return compareEveryItemInArrays(a, b, equals);
case '[object Object]':
return compareObjects(a, b, equals);
case '[object Function]':
return a.toString() === b.toString();
} // If we made it this far, we can't handle it
return false;
}
module.exports = {
lessThan: lessThan,
lessThanOrEquals: lessThanOrEquals,
greaterThan: greaterThan,
greaterThanOrEquals: greaterThanOrEquals,
equivalent: equivalent,
equals: equals
};