cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
727 lines (632 loc) • 23.1 kB
JavaScript
// Generated by CoffeeScript 1.12.7
(function() {
var Collapse, End, Ends, Expand, Expression, Interval, MIN_FLOAT_PRECISION_VALUE, Meets, MeetsAfter, MeetsBefore, Overlaps, OverlapsAfter, OverlapsBefore, Quantity, Start, Starts, ThreeValuedLogic, UnimplementedExpression, Width, build, cmp, collapseIntervals, compare_units, convert_value, doAddition, doIncludes, doSubtraction, dtivl, intervalListType, predecessor, ref, ref1, ref2, successor,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
ref = require('./expression'), Expression = ref.Expression, UnimplementedExpression = ref.UnimplementedExpression;
ThreeValuedLogic = require('../datatypes/logic').ThreeValuedLogic;
build = require('./builder').build;
ref1 = require('./quantity'), Quantity = ref1.Quantity, doAddition = ref1.doAddition, doSubtraction = ref1.doSubtraction, compare_units = ref1.compare_units, convert_value = ref1.convert_value;
ref2 = require('../util/math'), successor = ref2.successor, predecessor = ref2.predecessor, MIN_FLOAT_PRECISION_VALUE = ref2.MIN_FLOAT_PRECISION_VALUE;
dtivl = require('../datatypes/interval');
cmp = require('../util/comparison');
module.exports.Interval = Interval = (function(superClass) {
extend(Interval, superClass);
function Interval(json) {
Interval.__super__.constructor.apply(this, arguments);
this.lowClosed = json.lowClosed;
this.highClosed = json.highClosed;
this.low = build(json.low);
this.high = build(json.high);
}
Object.defineProperties(Interval.prototype, {
isInterval: {
get: function() {
return true;
}
}
});
Interval.prototype.exec = function(ctx) {
return new dtivl.Interval(this.low.execute(ctx), this.high.execute(ctx), this.lowClosed, this.highClosed);
};
return Interval;
})(Expression);
module.exports.doContains = function(interval, item, precision) {
return interval.contains(item, precision);
};
module.exports.doIncludes = doIncludes = function(interval, subinterval, precision) {
return interval.includes(subinterval, precision);
};
module.exports.doProperIncludes = function(interval, subinterval, precision) {
return interval.properlyIncludes(subinterval, precision);
};
module.exports.doAfter = function(a, b, precision) {
return a.after(b, precision);
};
module.exports.doBefore = function(a, b, precision) {
return a.before(b, precision);
};
module.exports.Meets = Meets = (function(superClass) {
extend(Meets, superClass);
function Meets(json) {
var ref3;
Meets.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
Meets.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.meets(b, this.precision);
} else {
return null;
}
};
return Meets;
})(Expression);
module.exports.MeetsAfter = MeetsAfter = (function(superClass) {
extend(MeetsAfter, superClass);
function MeetsAfter(json) {
var ref3;
MeetsAfter.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
MeetsAfter.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.meetsAfter(b, this.precision);
} else {
return null;
}
};
return MeetsAfter;
})(Expression);
module.exports.MeetsBefore = MeetsBefore = (function(superClass) {
extend(MeetsBefore, superClass);
function MeetsBefore(json) {
var ref3;
MeetsBefore.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
MeetsBefore.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.meetsBefore(b, this.precision);
} else {
return null;
}
};
return MeetsBefore;
})(Expression);
module.exports.Overlaps = Overlaps = (function(superClass) {
extend(Overlaps, superClass);
function Overlaps(json) {
var ref3;
Overlaps.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
Overlaps.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.overlaps(b, this.precision);
} else {
return null;
}
};
return Overlaps;
})(Expression);
module.exports.OverlapsAfter = OverlapsAfter = (function(superClass) {
extend(OverlapsAfter, superClass);
function OverlapsAfter(json) {
var ref3;
OverlapsAfter.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
OverlapsAfter.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.overlapsAfter(b, this.precision);
} else {
return null;
}
};
return OverlapsAfter;
})(Expression);
module.exports.OverlapsBefore = OverlapsBefore = (function(superClass) {
extend(OverlapsBefore, superClass);
function OverlapsBefore(json) {
var ref3;
OverlapsBefore.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
OverlapsBefore.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.overlapsBefore(b, this.precision);
} else {
return null;
}
};
return OverlapsBefore;
})(Expression);
module.exports.doUnion = function(a, b) {
return a.union(b);
};
module.exports.doExcept = function(a, b) {
if ((a != null) && (b != null)) {
return a.except(b);
} else {
return null;
}
};
module.exports.doIntersect = function(a, b) {
if ((a != null) && (b != null)) {
return a.intersect(b);
} else {
return null;
}
};
module.exports.Width = Width = (function(superClass) {
extend(Width, superClass);
function Width(json) {
Width.__super__.constructor.apply(this, arguments);
}
Width.prototype.exec = function(ctx) {
var ref3;
return (ref3 = this.arg.execute(ctx)) != null ? ref3.width() : void 0;
};
return Width;
})(Expression);
module.exports.Start = Start = (function(superClass) {
extend(Start, superClass);
function Start(json) {
Start.__super__.constructor.apply(this, arguments);
}
Start.prototype.exec = function(ctx) {
var interval;
interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
return interval.start();
};
return Start;
})(Expression);
module.exports.End = End = (function(superClass) {
extend(End, superClass);
function End(json) {
End.__super__.constructor.apply(this, arguments);
}
End.prototype.exec = function(ctx) {
var interval;
interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
return interval.end();
};
return End;
})(Expression);
module.exports.Starts = Starts = (function(superClass) {
extend(Starts, superClass);
function Starts(json) {
var ref3;
Starts.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
Starts.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.starts(b, this.precision);
} else {
return null;
}
};
return Starts;
})(Expression);
module.exports.Ends = Ends = (function(superClass) {
extend(Ends, superClass);
function Ends(json) {
var ref3;
Ends.__super__.constructor.apply(this, arguments);
this.precision = (ref3 = json.precision) != null ? ref3.toLowerCase() : void 0;
}
Ends.prototype.exec = function(ctx) {
var a, b, ref3;
ref3 = this.execArgs(ctx), a = ref3[0], b = ref3[1];
if ((a != null) && (b != null)) {
return a.ends(b, this.precision);
} else {
return null;
}
};
return Ends;
})(Expression);
intervalListType = function(intervals) {
var high, itvl, j, len, low, ref3, ref4, type;
type = null;
for (j = 0, len = intervals.length; j < len; j++) {
itvl = intervals[j];
if (itvl == null) {
continue;
}
if ((itvl.low == null) && (itvl.high == null)) {
continue;
}
low = (ref3 = itvl.low) != null ? ref3 : itvl.high;
high = (ref4 = itvl.high) != null ? ref4 : itvl.low;
if ((typeof low.isTime === "function" ? low.isTime() : void 0) && (typeof high.isTime === "function" ? high.isTime() : void 0)) {
if (type == null) {
type = 'time';
} else if (type === 'time') {
continue;
} else {
return 'mismatch';
}
} else if ((low.isDateTime || high.isDateTime) && (low.isDateTime || low.isDate) && (high.isDateTime || high.isDate)) {
if ((type == null) || type === 'date') {
type = 'datetime';
} else if (type === 'datetime') {
continue;
} else {
return 'mismatch';
}
} else if (low.isDate && high.isDate) {
if (type == null) {
type = 'date';
} else if (type === 'date' || 'datetime') {
continue;
} else {
return 'mismatch';
}
} else if (low.isQuantity && high.isQuantity) {
if (type == null) {
type = 'quantity';
} else if (type === 'quantity') {
continue;
} else {
return 'mismatch';
}
} else if (Number.isInteger(low) && Number.isInteger(high)) {
if (type == null) {
type = 'integer';
} else if (type === 'integer' || 'decimal') {
continue;
} else {
return 'mismatch';
}
} else if (typeof low === 'number' && typeof high === 'number') {
if ((type == null) || type === 'integer') {
type = 'decimal';
} else if (type === 'decimal') {
continue;
} else {
return 'mismatch';
}
} else {
return 'mismatch';
}
}
return type;
};
module.exports.Expand = Expand = (function(superClass) {
extend(Expand, superClass);
function Expand(json) {
Expand.__super__.constructor.apply(this, arguments);
}
Expand.prototype.exec = function(ctx) {
var defaultPer, expandFunction, interval, intervals, items, j, len, per, ref3, results, type;
ref3 = this.execArgs(ctx), intervals = ref3[0], per = ref3[1];
type = intervalListType(intervals);
if (type === 'mismatch') {
throw new Error("List of intervals contains mismatched types.");
}
if (type == null) {
return null;
}
intervals = collapseIntervals(intervals, per);
if (intervals.length === 0) {
return [];
}
if (type === "time" || type === "date" || type === "datetime") {
expandFunction = this.expandDTishInterval;
defaultPer = function(interval) {
return new Quantity({
value: 1,
unit: interval.low.getPrecision()
});
};
} else if (type === "quantity") {
expandFunction = this.expandQuantityInterval;
defaultPer = function(interval) {
return new Quantity({
value: 1,
unit: interval.low.unit
});
};
} else if (type === "integer" || type === "decimal") {
expandFunction = this.expandNumericInterval;
defaultPer = function(interval) {
return new Quantity({
value: 1,
unit: '1'
});
};
} else {
throw new Error("Interval list type not yet supported.");
}
results = [];
for (j = 0, len = intervals.length; j < len; j++) {
interval = intervals[j];
if (interval == null) {
continue;
}
if ((interval.low == null) || (interval.high == null)) {
return null;
}
if (type === 'datetime') {
interval.low = interval.low.getDateTime();
interval.high = interval.high.getDateTime();
}
per = per != null ? per : defaultPer(interval);
items = expandFunction.call(this, interval, per);
if (items === null) {
return null;
}
results.push.apply(results, items);
}
return results;
};
Expand.prototype.expandDTishInterval = function(interval, per) {
var count, current_high, current_low, high, i, j, k, low, point_intervals, ref3, ref4, ref5, ref6, results;
if ((ref3 = per.unit) === 'week' || ref3 === 'weeks') {
per.value *= 7;
per.unit = 'day';
}
if (ref4 = per.unit, indexOf.call(interval.low.constructor.FIELDS, ref4) < 0) {
return null;
}
if (interval.low.isLessPrecise(per.unit)) {
return null;
}
low = interval.lowClosed ? interval.low : interval.low.successor();
high = interval.highClosed ? interval.high : interval.high.predecessor();
if (low.after(high)) {
return [];
}
current_low = low;
results = [];
point_intervals = current_low.add(per.value, per.unit).predecessor().equals(current_low);
if (per.unit === low.getPrecision()) {
count = Math.floor((low.durationBetween(high, per.unit).high + 1) / per.value);
} else {
count = Math.floor((low.durationBetween(high, per.unit).low + 1) / per.value);
}
if (point_intervals) {
for (i = j = 1, ref5 = count + 1; 1 <= ref5 ? j <= ref5 : j >= ref5; i = 1 <= ref5 ? ++j : --j) {
results.push(new dtivl.Interval(current_low, current_low.copy(), true, true));
current_low = current_low.add(per.value, per.unit);
}
} else {
for (i = k = 1, ref6 = count; 1 <= ref6 ? k <= ref6 : k >= ref6; i = 1 <= ref6 ? ++k : --k) {
current_high = current_low.add(per.value, per.unit).predecessor();
results.push(new dtivl.Interval(current_low, current_high, true, true));
current_low = current_low.add(per.value, per.unit);
}
}
if (results.length > 0 && !results[results.length - 1].high.sameOrBefore(high)) {
results.pop();
}
return results;
};
Expand.prototype.expandQuantityInterval = function(interval, per) {
var high_value, itvl, j, len, low_value, per_value, result_units, results;
if (compare_units(interval.low.unit, per.unit) > 0) {
result_units = per.unit;
} else {
result_units = interval.low.unit;
}
low_value = convert_value(interval.low.value, interval.low.unit, result_units);
high_value = convert_value(interval.high.value, interval.high.unit, result_units);
per_value = convert_value(per.value, per.unit, result_units);
if (!((low_value != null) && (high_value != null) && (per_value != null))) {
return null;
}
results = this.makeNumericIntervalList(low_value, high_value, interval.lowClosed, interval.highClosed, per_value);
for (j = 0, len = results.length; j < len; j++) {
itvl = results[j];
itvl.low = new Quantity({
value: itvl.low,
unit: result_units
});
itvl.high = new Quantity({
value: itvl.high,
unit: result_units
});
}
return results;
};
Expand.prototype.expandNumericInterval = function(interval, per) {
if (per.unit !== '1') {
return null;
}
return this.makeNumericIntervalList(interval.low, interval.high, interval.lowClosed, interval.highClosed, per.value);
};
Expand.prototype.makeNumericIntervalList = function(low, high, lowClosed, highClosed, per) {
var gap, point_intervals, results, width, x;
point_intervals = Number.isInteger(low) && Number.isInteger(high) && Number.isInteger(per);
gap = point_intervals ? 1 : MIN_FLOAT_PRECISION_VALUE;
if (!lowClosed) {
low = low + gap;
}
if (!highClosed) {
high = high - gap;
}
width = per - gap;
if (low > high) {
return [];
}
results = (function() {
var j, ref3, ref4, ref5, results1;
results1 = [];
for (x = j = ref3 = low, ref4 = high - width, ref5 = per; ref5 > 0 ? j <= ref4 : j >= ref4; x = j += ref5) {
results1.push(new dtivl.Interval(x, x + width, true, true));
}
return results1;
})();
return results;
};
return Expand;
})(Expression);
module.exports.Collapse = Collapse = (function(superClass) {
extend(Collapse, superClass);
function Collapse(json) {
Collapse.__super__.constructor.apply(this, arguments);
}
Collapse.prototype.exec = function(ctx) {
var intervals, perWidth, ref3;
ref3 = this.execArgs(ctx), intervals = ref3[0], perWidth = ref3[1];
return collapseIntervals(intervals, perWidth);
};
return Collapse;
})(Expression);
collapseIntervals = function(intervals, perWidth) {
var a, b, collapsedIntervals, interval, intervalsClone, j, len, precisionUnits, ref3, ref4, ref5, ref6;
intervalsClone = [];
for (j = 0, len = intervals.length; j < len; j++) {
interval = intervals[j];
if (interval != null) {
intervalsClone.push(interval.copy());
}
}
if (intervals == null) {
return null;
} else if ((intervalsClone != null ? intervalsClone.length : void 0) <= 1) {
return intervalsClone;
} else {
if (perWidth == null) {
if (intervalsClone[0].low != null) {
if (intervalsClone[0].low.isDateTime) {
precisionUnits = intervalsClone[0].low.getPrecision();
perWidth = new Quantity({
value: 1,
unit: precisionUnits
});
} else if (intervalsClone[0].low.isQuantity) {
perWidth = doSubtraction(successor(intervalsClone[0].low), intervalsClone[0].low);
} else {
perWidth = successor(intervalsClone[0].low) - intervalsClone[0].low;
}
} else if (intervalsClone[0].high != null) {
if (intervalsClone[0].high.isDateTime) {
precisionUnits = intervalsClone[0].high.getPrecision();
perWidth = new Quantity({
value: 1,
unit: precisionUnits
});
} else if (intervalsClone[0].high.isQuantity) {
perWidth = doSubtraction(successor(intervalsClone[0].high), intervalsClone[0].high);
} else {
perWidth = successor(intervalsClone[0].high) - intervalsClone[0].high;
}
} else {
throw new Error("Point type of intervals provided to collapse cannot be determined.");
}
if (typeof perWidth === 'number') {
perWidth = new Quantity({
value: perWidth,
unit: '1'
});
}
}
intervalsClone.sort(function(a, b) {
var ref3, ref4;
if (typeof ((ref3 = a.low) != null ? ref3.before : void 0) === 'function') {
if ((b.low != null) && a.low.before(b.low)) {
return -1;
}
if ((b.low == null) || a.low.after(b.low)) {
return 1;
}
} else if ((a.low != null) && (b.low != null)) {
if (a.low < b.low) {
return -1;
}
if (a.low > b.low) {
return 1;
}
} else if ((a.low != null) && (b.low == null)) {
return 1;
} else if ((a.low == null) && (b.low != null)) {
return -1;
}
if (typeof ((ref4 = a.high) != null ? ref4.before : void 0) === 'function') {
if ((b.high == null) || a.high.before(b.high)) {
return -1;
}
if (a.high.after(b.high)) {
return 1;
}
} else if ((a.high != null) && (b.high != null)) {
if (a.high < b.high) {
return -1;
}
if (a.high > b.high) {
return 1;
}
} else if ((a.high != null) && (b.high == null)) {
return -1;
} else if ((a.high == null) && (b.high != null)) {
return 1;
}
return 0;
});
collapsedIntervals = [];
a = intervalsClone.shift();
b = intervalsClone.shift();
while (b) {
if (typeof ((ref3 = b.low) != null ? ref3.durationBetween : void 0) === 'function') {
if ((ref4 = a.high) != null ? ref4.sameOrAfter(b.low) : void 0) {
if ((b.high == null) || b.high.after(a.high)) {
a.high = b.high;
}
} else if (((ref5 = a.high) != null ? ref5.durationBetween(b.low, perWidth.unit).high : void 0) <= perWidth.value) {
a.high = b.high;
} else {
collapsedIntervals.push(a);
a = b;
}
} else if (typeof ((ref6 = b.low) != null ? ref6.sameOrBefore : void 0) === 'function') {
if ((a.high != null) && b.low.sameOrBefore(doAddition(a.high, perWidth))) {
if ((b.high == null) || b.high.after(a.high)) {
a.high = b.high;
}
} else {
collapsedIntervals.push(a);
a = b;
}
} else {
if ((b.low - a.high) <= perWidth.value) {
if (b.high > a.high || (b.high == null)) {
a.high = b.high;
}
} else {
collapsedIntervals.push(a);
a = b;
}
}
b = intervalsClone.shift();
}
collapsedIntervals.push(a);
return collapsedIntervals;
}
};
}).call(this);
//# sourceMappingURL=interval.js.map