@phema/cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
291 lines (241 loc) • 9.83 kB
JavaScript
"use strict";
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; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var _require = require('../util/math'),
decimalAdjust = _require.decimalAdjust,
isValidDecimal = _require.isValidDecimal,
overflowsOrUnderflows = _require.overflowsOrUnderflows;
var _require2 = require('../util/units'),
checkUnit = _require2.checkUnit,
_convertUnit = _require2.convertUnit,
normalizeUnitsWhenPossible = _require2.normalizeUnitsWhenPossible,
convertToCQLDateUnit = _require2.convertToCQLDateUnit,
getProductOfUnits = _require2.getProductOfUnits,
getQuotientOfUnits = _require2.getQuotientOfUnits;
var Quantity = /*#__PURE__*/function () {
function Quantity(value, unit) {
_classCallCheck(this, Quantity);
this.value = value;
this.unit = unit;
if (this.value == null || isNaN(this.value)) {
throw new Error('Cannot create a quantity with an undefined value');
} else if (!isValidDecimal(this.value)) {
throw new Error('Cannot create a quantity with an invalid decimal value');
} // Attempt to parse the unit with UCUM. If it fails, throw a friendly error.
if (this.unit != null) {
var validation = checkUnit(this.unit);
if (!validation.valid) {
throw new Error(validation.message);
}
}
}
_createClass(Quantity, [{
key: "isQuantity",
get: function get() {
return true;
}
}, {
key: "clone",
value: function clone() {
return new Quantity(this.value, this.unit);
}
}, {
key: "toString",
value: function toString() {
return "".concat(this.value, " '").concat(this.unit, "'");
}
}, {
key: "sameOrBefore",
value: function sameOrBefore(other) {
if (other != null && other.isQuantity) {
var otherVal = _convertUnit(other.value, other.unit, this.unit);
if (otherVal == null) {
return null;
} else {
return this.value <= otherVal;
}
}
}
}, {
key: "sameOrAfter",
value: function sameOrAfter(other) {
if (other != null && other.isQuantity) {
var otherVal = _convertUnit(other.value, other.unit, this.unit);
if (otherVal == null) {
return null;
} else {
return this.value >= otherVal;
}
}
}
}, {
key: "after",
value: function after(other) {
if (other != null && other.isQuantity) {
var otherVal = _convertUnit(other.value, other.unit, this.unit);
if (otherVal == null) {
return null;
} else {
return this.value > otherVal;
}
}
}
}, {
key: "before",
value: function before(other) {
if (other != null && other.isQuantity) {
var otherVal = _convertUnit(other.value, other.unit, this.unit);
if (otherVal == null) {
return null;
} else {
return this.value < otherVal;
}
}
}
}, {
key: "equals",
value: function equals(other) {
if (other != null && other.isQuantity) {
if (!this.unit && other.unit || this.unit && !other.unit) {
return false;
} else if (!this.unit && !other.unit) {
return this.value === other.value;
} else {
var otherVal = _convertUnit(other.value, other.unit, this.unit);
if (otherVal == null) {
return null;
} else {
return decimalAdjust('round', this.value, -8) === otherVal;
}
}
}
}
}, {
key: "convertUnit",
value: function convertUnit(toUnit) {
var value = _convertUnit(this.value, this.unit, toUnit); // Need to pass through constructor again to catch invalid units
return new Quantity(value, toUnit);
}
}, {
key: "dividedBy",
value: function dividedBy(other) {
if (other == null || other === 0 || other.value === 0) {
return null;
} else if (!other.isQuantity) {
// convert it to a quantity w/ unit 1
other = new Quantity(other, '1');
}
var _normalizeUnitsWhenPo = normalizeUnitsWhenPossible(this.value, this.unit, other.value, other.unit),
_normalizeUnitsWhenPo2 = _slicedToArray(_normalizeUnitsWhenPo, 4),
val1 = _normalizeUnitsWhenPo2[0],
unit1 = _normalizeUnitsWhenPo2[1],
val2 = _normalizeUnitsWhenPo2[2],
unit2 = _normalizeUnitsWhenPo2[3];
var resultValue = val1 / val2;
var resultUnit = getQuotientOfUnits(unit1, unit2); // Check for invalid unit or value
if (resultUnit == null || overflowsOrUnderflows(resultValue)) {
return null;
}
return new Quantity(decimalAdjust('round', resultValue, -8), resultUnit);
}
}, {
key: "multiplyBy",
value: function multiplyBy(other) {
if (other == null) {
return null;
} else if (!other.isQuantity) {
// convert it to a quantity w/ unit 1
other = new Quantity(other, '1');
}
var _normalizeUnitsWhenPo3 = normalizeUnitsWhenPossible(this.value, this.unit, other.value, other.unit),
_normalizeUnitsWhenPo4 = _slicedToArray(_normalizeUnitsWhenPo3, 4),
val1 = _normalizeUnitsWhenPo4[0],
unit1 = _normalizeUnitsWhenPo4[1],
val2 = _normalizeUnitsWhenPo4[2],
unit2 = _normalizeUnitsWhenPo4[3];
var resultValue = val1 * val2;
var resultUnit = getProductOfUnits(unit1, unit2); // Check for invalid unit or value
if (resultUnit == null || overflowsOrUnderflows(resultValue)) {
return null;
}
return new Quantity(decimalAdjust('round', resultValue, -8), resultUnit);
}
}]);
return Quantity;
}();
function parseQuantity(str) {
var components = /([+|-]?\d+\.?\d*)\s*('(.+)')?/.exec(str);
if (components != null && components[1] != null) {
var value = parseFloat(components[1]);
if (!isValidDecimal(value)) {
return null;
}
var unit;
if (components[3] != null) {
unit = components[3].trim();
} else {
unit = '';
}
return new Quantity(value, unit);
} else {
return null;
}
}
function doScaledAddition(a, b, scaleForB) {
if (a != null && a.isQuantity && b != null && b.isQuantity) {
var _normalizeUnitsWhenPo5 = normalizeUnitsWhenPossible(a.value, a.unit, b.value * scaleForB, b.unit),
_normalizeUnitsWhenPo6 = _slicedToArray(_normalizeUnitsWhenPo5, 4),
val1 = _normalizeUnitsWhenPo6[0],
unit1 = _normalizeUnitsWhenPo6[1],
val2 = _normalizeUnitsWhenPo6[2],
unit2 = _normalizeUnitsWhenPo6[3];
if (unit1 !== unit2) {
// not compatible units, so we can't do addition
return null;
}
var sum = val1 + val2;
if (overflowsOrUnderflows(sum)) {
return null;
}
return new Quantity(sum, unit1);
} else if (a.copy && a.add) {
// Date / DateTime require a CQL time unit
var cqlUnitB = convertToCQLDateUnit(b.unit) || b.unit;
return a.copy().add(b.value * scaleForB, cqlUnitB);
} else {
throw new Error('Unsupported argument types.');
}
}
function doAddition(a, b) {
return doScaledAddition(a, b, 1);
}
function doSubtraction(a, b) {
return doScaledAddition(a, b, -1);
}
function doDivision(a, b) {
if (a != null && a.isQuantity) {
return a.dividedBy(b);
}
}
function doMultiplication(a, b) {
if (a != null && a.isQuantity) {
return a.multiplyBy(b);
} else {
return b.multiplyBy(a);
}
}
module.exports = {
Quantity: Quantity,
parseQuantity: parseQuantity,
doAddition: doAddition,
doSubtraction: doSubtraction,
doDivision: doDivision,
doMultiplication: doMultiplication
};