cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
481 lines • 15.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Predecessor = exports.Successor = exports.MaxValue = exports.MinValue = exports.Power = exports.Log = exports.Exp = exports.Ln = exports.Round = exports.Negate = exports.Abs = exports.Truncate = exports.Floor = exports.Ceiling = exports.Modulo = exports.TruncatedDivide = exports.Divide = exports.Multiply = exports.Subtract = exports.Add = void 0;
const expression_1 = require("./expression");
const MathUtil = __importStar(require("../util/math"));
const quantity_1 = require("../datatypes/quantity");
const uncertainty_1 = require("../datatypes/uncertainty");
const builder_1 = require("./builder");
class Add extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const sum = args.reduce((x, y) => {
if (x.isUncertainty && !y.isUncertainty) {
y = new uncertainty_1.Uncertainty(y, y);
}
else if (y.isUncertainty && !x.isUncertainty) {
x = new uncertainty_1.Uncertainty(x, x);
}
if (x.isQuantity || x.isDateTime || x.isDate || (x.isTime && x.isTime())) {
return (0, quantity_1.doAddition)(x, y);
}
else if (x.isUncertainty && y.isUncertainty) {
if (x.low.isQuantity ||
x.low.isDateTime ||
x.low.isDate ||
(x.low.isTime && x.low.isTime())) {
return new uncertainty_1.Uncertainty((0, quantity_1.doAddition)(x.low, y.low), (0, quantity_1.doAddition)(x.high, y.high));
}
else {
return new uncertainty_1.Uncertainty(x.low + y.low, x.high + y.high);
}
}
else {
return x + y;
}
});
if (MathUtil.overflowsOrUnderflows(sum)) {
return null;
}
return sum;
}
}
exports.Add = Add;
class Subtract extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const difference = args.reduce((x, y) => {
if (x.isUncertainty && !y.isUncertainty) {
y = new uncertainty_1.Uncertainty(y, y);
}
else if (y.isUncertainty && !x.isUncertainty) {
x = new uncertainty_1.Uncertainty(x, x);
}
if (x.isQuantity || x.isDateTime || x.isDate) {
return (0, quantity_1.doSubtraction)(x, y);
}
else if (x.isUncertainty && y.isUncertainty) {
if (x.low.isQuantity || x.low.isDateTime || x.low.isDate) {
return new uncertainty_1.Uncertainty((0, quantity_1.doSubtraction)(x.low, y.high), (0, quantity_1.doSubtraction)(x.high, y.low));
}
else {
return new uncertainty_1.Uncertainty(x.low - y.high, x.high - y.low);
}
}
else {
return x - y;
}
});
if (MathUtil.overflowsOrUnderflows(difference)) {
return null;
}
return difference;
}
}
exports.Subtract = Subtract;
class Multiply extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const product = args.reduce((x, y) => {
if (x.isUncertainty && !y.isUncertainty) {
y = new uncertainty_1.Uncertainty(y, y);
}
else if (y.isUncertainty && !x.isUncertainty) {
x = new uncertainty_1.Uncertainty(x, x);
}
if (x.isQuantity || y.isQuantity) {
return (0, quantity_1.doMultiplication)(x, y);
}
else if (x.isUncertainty && y.isUncertainty) {
if (x.low.isQuantity) {
return new uncertainty_1.Uncertainty((0, quantity_1.doMultiplication)(x.low, y.low), (0, quantity_1.doMultiplication)(x.high, y.high));
}
else {
return new uncertainty_1.Uncertainty(x.low * y.low, x.high * y.high);
}
}
else {
return x * y;
}
});
if (MathUtil.overflowsOrUnderflows(product)) {
return null;
}
return product;
}
}
exports.Multiply = Multiply;
class Divide extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const quotient = args.reduce((x, y) => {
if (x.isUncertainty && !y.isUncertainty) {
y = new uncertainty_1.Uncertainty(y, y);
}
else if (y.isUncertainty && !x.isUncertainty) {
x = new uncertainty_1.Uncertainty(x, x);
}
if (x.isQuantity) {
return (0, quantity_1.doDivision)(x, y);
}
else if (x.isUncertainty && y.isUncertainty) {
if (x.low.isQuantity) {
return new uncertainty_1.Uncertainty((0, quantity_1.doDivision)(x.low, y.high), (0, quantity_1.doDivision)(x.high, y.low));
}
else {
return new uncertainty_1.Uncertainty(x.low / y.high, x.high / y.low);
}
}
else {
return x / y;
}
});
// Note, anything divided by 0 is Infinity in Javascript, which will be
// considered as overflow by this check.
if (MathUtil.overflowsOrUnderflows(quotient)) {
return null;
}
return quotient;
}
}
exports.Divide = Divide;
class TruncatedDivide extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const quotient = args.reduce((x, y) => x / y);
const truncatedQuotient = quotient >= 0 ? Math.floor(quotient) : Math.ceil(quotient);
if (MathUtil.overflowsOrUnderflows(truncatedQuotient)) {
return null;
}
return truncatedQuotient;
}
}
exports.TruncatedDivide = TruncatedDivide;
class Modulo extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const modulo = args.reduce((x, y) => x % y);
return MathUtil.decimalOrNull(modulo);
}
}
exports.Modulo = Modulo;
class Ceiling extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
return Math.ceil(arg);
}
}
exports.Ceiling = Ceiling;
class Floor extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
return Math.floor(arg);
}
}
exports.Floor = Floor;
class Truncate extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
return arg >= 0 ? Math.floor(arg) : Math.ceil(arg);
}
}
exports.Truncate = Truncate;
class Abs extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
else if (arg.isQuantity) {
return new quantity_1.Quantity(Math.abs(arg.value), arg.unit);
}
else {
return Math.abs(arg);
}
}
}
exports.Abs = Abs;
class Negate extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
else if (arg.isQuantity) {
return new quantity_1.Quantity(arg.value * -1, arg.unit);
}
else {
return arg * -1;
}
}
}
exports.Negate = Negate;
class Round extends expression_1.Expression {
constructor(json) {
super(json);
this.precision = (0, builder_1.build)(json.precision);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
const dec = this.precision != null ? await this.precision.execute(ctx) : 0;
return Math.round(arg * Math.pow(10, dec)) / Math.pow(10, dec);
}
}
exports.Round = Round;
class Ln extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
const ln = Math.log(arg);
return MathUtil.decimalOrNull(ln);
}
}
exports.Ln = Ln;
class Exp extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
const power = Math.exp(arg);
if (MathUtil.overflowsOrUnderflows(power)) {
return null;
}
return power;
}
}
exports.Exp = Exp;
class Log extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const log = args.reduce((x, y) => Math.log(x) / Math.log(y));
return MathUtil.decimalOrNull(log);
}
}
exports.Log = Log;
class Power extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const args = await this.execArgs(ctx);
if (args == null || args.some((x) => x == null)) {
return null;
}
const power = args.reduce((x, y) => Math.pow(x, y));
if (MathUtil.overflowsOrUnderflows(power)) {
return null;
}
return power;
}
}
exports.Power = Power;
class MinValue extends expression_1.Expression {
constructor(json) {
super(json);
this.valueType = json.valueType;
}
async exec(ctx) {
if (MinValue.MIN_VALUES[this.valueType]) {
if (this.valueType === '{urn:hl7-org:elm-types:r1}DateTime') {
const minDateTime = MinValue.MIN_VALUES[this.valueType].copy();
minDateTime.timezoneOffset = ctx.getTimezoneOffset();
return minDateTime;
}
else {
return MinValue.MIN_VALUES[this.valueType];
}
}
else {
throw new Error(`Minimum not supported for ${this.valueType}`);
}
}
}
exports.MinValue = MinValue;
MinValue.MIN_VALUES = {
'{urn:hl7-org:elm-types:r1}Integer': MathUtil.MIN_INT_VALUE,
'{urn:hl7-org:elm-types:r1}Decimal': MathUtil.MIN_FLOAT_VALUE,
'{urn:hl7-org:elm-types:r1}DateTime': MathUtil.MIN_DATETIME_VALUE,
'{urn:hl7-org:elm-types:r1}Date': MathUtil.MIN_DATE_VALUE,
'{urn:hl7-org:elm-types:r1}Time': MathUtil.MIN_TIME_VALUE
};
class MaxValue extends expression_1.Expression {
constructor(json) {
super(json);
this.valueType = json.valueType;
}
async exec(ctx) {
if (MaxValue.MAX_VALUES[this.valueType] != null) {
if (this.valueType === '{urn:hl7-org:elm-types:r1}DateTime') {
const maxDateTime = MaxValue.MAX_VALUES[this.valueType].copy();
maxDateTime.timezoneOffset = ctx.getTimezoneOffset();
return maxDateTime;
}
else {
return MaxValue.MAX_VALUES[this.valueType];
}
}
else {
throw new Error(`Maximum not supported for ${this.valueType}`);
}
}
}
exports.MaxValue = MaxValue;
MaxValue.MAX_VALUES = {
'{urn:hl7-org:elm-types:r1}Integer': MathUtil.MAX_INT_VALUE,
'{urn:hl7-org:elm-types:r1}Decimal': MathUtil.MAX_FLOAT_VALUE,
'{urn:hl7-org:elm-types:r1}DateTime': MathUtil.MAX_DATETIME_VALUE,
'{urn:hl7-org:elm-types:r1}Date': MathUtil.MAX_DATE_VALUE,
'{urn:hl7-org:elm-types:r1}Time': MathUtil.MAX_TIME_VALUE
};
class Successor extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
let successor = null;
try {
// MathUtil.successor throws on overflow, and the exception is used in
// the logic for evaluating `meets`, so it can't be changed to just return null
successor = MathUtil.successor(arg);
}
catch (e) {
if (e instanceof MathUtil.OverFlowException) {
return null;
}
}
if (MathUtil.overflowsOrUnderflows(successor)) {
return null;
}
return successor;
}
}
exports.Successor = Successor;
class Predecessor extends expression_1.Expression {
constructor(json) {
super(json);
}
async exec(ctx) {
const arg = await this.execArgs(ctx);
if (arg == null) {
return null;
}
let predecessor = null;
try {
// MathUtil.predecessor throws on underflow, and the exception is used in
// the logic for evaluating `meets`, so it can't be changed to just return null
predecessor = MathUtil.predecessor(arg);
}
catch (e) {
if (e instanceof MathUtil.OverFlowException) {
return null;
}
}
if (MathUtil.overflowsOrUnderflows(predecessor)) {
return null;
}
return predecessor;
}
}
exports.Predecessor = Predecessor;
//# sourceMappingURL=arithmetic.js.map