UNPKG

@phema/cql-execution

Version:

An execution framework for the Clinical Quality Language (CQL)

422 lines (355 loc) 12.8 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } var _require = require('../datatypes/exception'), Exception = _require.Exception; var _require2 = require('../datatypes/datetime'), MIN_DATETIME_VALUE = _require2.MIN_DATETIME_VALUE, MAX_DATETIME_VALUE = _require2.MAX_DATETIME_VALUE, MIN_DATE_VALUE = _require2.MIN_DATE_VALUE, MAX_DATE_VALUE = _require2.MAX_DATE_VALUE, MIN_TIME_VALUE = _require2.MIN_TIME_VALUE, MAX_TIME_VALUE = _require2.MAX_TIME_VALUE; var _require3 = require('../datatypes/uncertainty'), Uncertainty = _require3.Uncertainty; var MAX_INT_VALUE = Math.pow(2, 31) - 1; var MIN_INT_VALUE = Math.pow(-2, 31); var MAX_FLOAT_VALUE = 99999999999999999999.99999999; var MIN_FLOAT_VALUE = -99999999999999999999.99999999; var MIN_FLOAT_PRECISION_VALUE = Math.pow(10, -8); function overflowsOrUnderflows(value) { if (value == null) { return false; } if (value.isQuantity) { if (!isValidDecimal(value.value)) { return true; } } else if (value.isTime && value.isTime()) { if (value.after(MAX_TIME_VALUE)) { return true; } if (value.before(MIN_TIME_VALUE)) { return true; } } else if (value.isDateTime) { if (value.after(MAX_DATETIME_VALUE)) { return true; } if (value.before(MIN_DATETIME_VALUE)) { return true; } } else if (value.isDate) { if (value.after(MAX_DATE_VALUE)) { return true; } if (value.before(MIN_DATE_VALUE)) { return true; } } else if (Number.isInteger(value)) { if (!isValidInteger(value)) { return true; } } else if (value.isUncertainty) { return overflowsOrUnderflows(value.low) || overflowsOrUnderflows(value.high); } else { if (!isValidDecimal(value)) { return true; } } return false; } function isValidInteger(integer) { if (isNaN(integer)) { return false; } if (integer > MAX_INT_VALUE) { return false; } if (integer < MIN_INT_VALUE) { return false; } return true; } function isValidDecimal(decimal) { if (isNaN(decimal)) { return false; } if (decimal > MAX_FLOAT_VALUE) { return false; } if (decimal < MIN_FLOAT_VALUE) { return false; } return true; } function limitDecimalPrecision(decimal) { var decimalString = decimal.toString(); // For decimals so large that they are represented in scientific notation, javascript has already limited // the decimal to its own constraints, so we can't determine the original precision. Leave as-is unless // this becomes problematic, in which case we would need our own parseFloat. if (decimalString.indexOf('e') !== -1) { return decimal; } var splitDecimalString = decimalString.split('.'); var decimalPoints = splitDecimalString[1]; if (decimalPoints != null && decimalPoints.length > 8) { decimalString = splitDecimalString[0] + '.' + splitDecimalString[1].substring(0, 8); } return parseFloat(decimalString); } var OverFlowException = /*#__PURE__*/function (_Exception) { _inherits(OverFlowException, _Exception); var _super = _createSuper(OverFlowException); function OverFlowException() { _classCallCheck(this, OverFlowException); return _super.apply(this, arguments); } return OverFlowException; }(Exception); function successor(val) { if (typeof val === 'number') { if (parseInt(val) === val) { if (val >= MAX_INT_VALUE) { throw new OverFlowException(); } else { return val + 1; } } else { if (val >= MAX_FLOAT_VALUE) { throw new OverFlowException(); } else { return val + MIN_FLOAT_PRECISION_VALUE; } } } else if (val && val.isTime && val.isTime()) { if (val.sameAs(MAX_TIME_VALUE)) { throw new OverFlowException(); } else { return val.successor(); } } else if (val && val.isDateTime) { if (val.sameAs(MAX_DATETIME_VALUE)) { throw new OverFlowException(); } else { return val.successor(); } } else if (val && val.isDate) { if (val.sameAs(MAX_DATE_VALUE)) { throw new OverFlowException(); } else { return val.successor(); } } else if (val && val.isUncertainty) { // For uncertainties, if the high is the max val, don't increment it var high = function () { try { return successor(val.high); } catch (e) { return val.high; } }(); return new Uncertainty(successor(val.low), high); } else if (val && val.isQuantity) { var succ = val.clone(); succ.value = successor(val.value); return succ; } else if (val == null) { return null; } } function predecessor(val) { if (typeof val === 'number') { if (parseInt(val) === val) { if (val <= MIN_INT_VALUE) { throw new OverFlowException(); } else { return val - 1; } } else { if (val <= MIN_FLOAT_VALUE) { throw new OverFlowException(); } else { return val - MIN_FLOAT_PRECISION_VALUE; } } } else if (val && val.isTime && val.isTime()) { if (val.sameAs(MIN_TIME_VALUE)) { throw new OverFlowException(); } else { return val.predecessor(); } } else if (val && val.isDateTime) { if (val.sameAs(MIN_DATETIME_VALUE)) { throw new OverFlowException(); } else { return val.predecessor(); } } else if (val && val.isDate) { if (val.sameAs(MIN_DATE_VALUE)) { throw new OverFlowException(); } else { return val.predecessor(); } } else if (val && val.isUncertainty) { // For uncertainties, if the low is the min val, don't decrement it var low = function () { try { return predecessor(val.low); } catch (e) { return val.low; } }(); return new Uncertainty(low, predecessor(val.high)); } else if (val && val.isQuantity) { var pred = val.clone(); pred.value = predecessor(val.value); return pred; } else if (val == null) { return null; } } function maxValueForInstance(val) { if (typeof val === 'number') { if (parseInt(val) === val) { return MAX_INT_VALUE; } else { return MAX_FLOAT_VALUE; } } else if (val && val.isTime && val.isTime()) { return MAX_TIME_VALUE.copy(); } else if (val && val.isDateTime) { return MAX_DATETIME_VALUE.copy(); } else if (val && val.isDate) { return MAX_DATE_VALUE.copy(); } else if (val && val.isQuantity) { var val2 = val.clone(); val2.value = maxValueForInstance(val2.value); return val2; } else { return null; } } function maxValueForType(type, quantityInstance) { switch (type) { case '{urn:hl7-org:elm-types:r1}Integer': return MAX_INT_VALUE; case '{urn:hl7-org:elm-types:r1}Decimal': return MAX_FLOAT_VALUE; case '{urn:hl7-org:elm-types:r1}DateTime': return MAX_DATETIME_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Date': return MAX_DATE_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Time': return MAX_TIME_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Quantity': { if (quantityInstance == null) { // can't infer a quantity unit type from nothing] return null; } var maxQty = quantityInstance.clone(); maxQty.value = maxValueForInstance(maxQty.value); return maxQty; } } return null; } function minValueForInstance(val) { if (typeof val === 'number') { if (parseInt(val) === val) { return MIN_INT_VALUE; } else { return MIN_FLOAT_VALUE; } } else if (val && val.isTime && val.isTime()) { return MIN_TIME_VALUE.copy(); } else if (val && val.isDateTime) { return MIN_DATETIME_VALUE.copy(); } else if (val && val.isDate) { return MIN_DATE_VALUE.copy(); } else if (val && val.isQuantity) { var val2 = val.clone(); val2.value = minValueForInstance(val2.value); return val2; } else { return null; } } function minValueForType(type, quantityInstance) { switch (type) { case '{urn:hl7-org:elm-types:r1}Integer': return MIN_INT_VALUE; case '{urn:hl7-org:elm-types:r1}Decimal': return MIN_FLOAT_VALUE; case '{urn:hl7-org:elm-types:r1}DateTime': return MIN_DATETIME_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Date': return MIN_DATE_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Time': return MIN_TIME_VALUE.copy(); case '{urn:hl7-org:elm-types:r1}Quantity': { if (quantityInstance == null) { // can't infer a quantity unit type from nothing] return null; } var minQty = quantityInstance.clone(); minQty.value = minValueForInstance(minQty.value); return minQty; } } return null; } function decimalAdjust(type, value, exp) { //If the exp is undefined or zero... if (typeof exp === 'undefined' || +exp === 0) { return Math[type](value); } value = +value; exp = +exp; //If the value is not a number or the exp is not an integer... if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) { return NaN; } //Shift value = value.toString().split('e'); var v = value[1] ? +value[1] - exp : -exp; value = Math[type](+(value[0] + 'e' + v)); //Shift back value = value.toString().split('e'); v = value[1] ? +value[1] + exp : exp; return +(value[0] + 'e' + v); } function decimalOrNull(value) { return isValidDecimal(value) ? value : null; } module.exports = { MAX_INT_VALUE: MAX_INT_VALUE, MIN_INT_VALUE: MIN_INT_VALUE, MAX_FLOAT_VALUE: MAX_FLOAT_VALUE, MIN_FLOAT_VALUE: MIN_FLOAT_VALUE, MIN_FLOAT_PRECISION_VALUE: MIN_FLOAT_PRECISION_VALUE, MIN_DATETIME_VALUE: MIN_DATETIME_VALUE, MAX_DATETIME_VALUE: MAX_DATETIME_VALUE, MIN_DATE_VALUE: MIN_DATE_VALUE, MAX_DATE_VALUE: MAX_DATE_VALUE, MIN_TIME_VALUE: MIN_TIME_VALUE, MAX_TIME_VALUE: MAX_TIME_VALUE, overflowsOrUnderflows: overflowsOrUnderflows, isValidInteger: isValidInteger, isValidDecimal: isValidDecimal, limitDecimalPrecision: limitDecimalPrecision, OverFlowException: OverFlowException, successor: successor, predecessor: predecessor, maxValueForInstance: maxValueForInstance, minValueForInstance: minValueForInstance, maxValueForType: maxValueForType, minValueForType: minValueForType, decimalAdjust: decimalAdjust, decimalOrNull: decimalOrNull };