@phema/cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
422 lines (355 loc) • 12.8 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 _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
};