UNPKG

@phema/cql-execution

Version:

An execution framework for the Clinical Quality Language (CQL)

300 lines (231 loc) 9.42 kB
"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 };