@phema/cql-execution
Version:
An execution framework for the Clinical Quality Language (CQL)
1,129 lines (872 loc) • 35.7 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 _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
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; }
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('./expression'),
Expression = _require.Expression;
var _require2 = require('./builder'),
build = _require2.build;
var _require3 = require('../datatypes/quantity'),
Quantity = _require3.Quantity,
doAddition = _require3.doAddition;
var _require4 = require('../util/math'),
successor = _require4.successor,
predecessor = _require4.predecessor,
MAX_DATETIME_VALUE = _require4.MAX_DATETIME_VALUE,
MIN_DATETIME_VALUE = _require4.MIN_DATETIME_VALUE;
var _require5 = require('../util/units'),
convertUnit = _require5.convertUnit,
compareUnits = _require5.compareUnits,
convertToCQLDateUnit = _require5.convertToCQLDateUnit;
var dtivl = require('../datatypes/interval');
var Interval = /*#__PURE__*/function (_Expression) {
_inherits(Interval, _Expression);
var _super = _createSuper(Interval);
function Interval(json) {
var _this;
_classCallCheck(this, Interval);
_this = _super.call(this, json);
_this.lowClosed = json.lowClosed;
_this.lowClosedExpression = build(json.lowClosedExpression);
_this.highClosed = json.highClosed;
_this.highClosedExpression = build(json.highClosedExpression);
_this.low = build(json.low);
_this.high = build(json.high);
return _this;
} // Define a simple getter to allow type-checking of this class without instanceof
// and in a way that survives minification (as opposed to checking constructor.name)
_createClass(Interval, [{
key: "isInterval",
get: function get() {
return true;
}
}, {
key: "exec",
value: function exec(ctx) {
var lowValue = this.low.execute(ctx);
var highValue = this.high.execute(ctx);
var lowClosed = this.lowClosed != null ? this.lowClosed : this.lowClosedExpression && this.lowClosedExpression.execute(ctx);
var highClosed = this.highClosed != null ? this.highClosed : this.highClosedExpression && this.highClosedExpression.execute(ctx);
var defaultPointType;
if (lowValue == null && highValue == null) {
// try to get the default point type from a cast
if (this.low.asTypeSpecifier && this.low.asTypeSpecifier.type === 'NamedTypeSpecifier') {
defaultPointType = this.low.asTypeSpecifier.name;
} else if (this.high.asTypeSpecifier && this.high.asTypeSpecifier.type === 'NamedTypeSpecifier') {
defaultPointType = this.high.asTypeSpecifier.name;
}
}
return new dtivl.Interval(lowValue, highValue, lowClosed, highClosed, defaultPointType);
}
}]);
return Interval;
}(Expression); // Equal is completely handled by overloaded#Equal
// NotEqual is completely handled by overloaded#Equal
// Delegated to by overloaded#Contains and overloaded#In
function doContains(interval, item, precision) {
return interval.contains(item, precision);
} // Delegated to by overloaded#Includes and overloaded#IncludedIn
function doIncludes(interval, subinterval, precision) {
return interval.includes(subinterval, precision);
} // Delegated to by overloaded#ProperIncludes and overloaded@ProperIncludedIn
function doProperIncludes(interval, subinterval, precision) {
return interval.properlyIncludes(subinterval, precision);
} // Delegated to by overloaded#After
function doAfter(a, b, precision) {
return a.after(b, precision);
} // Delegated to by overloaded#Before
function doBefore(a, b, precision) {
return a.before(b, precision);
}
var Meets = /*#__PURE__*/function (_Expression2) {
_inherits(Meets, _Expression2);
var _super2 = _createSuper(Meets);
function Meets(json) {
var _this2;
_classCallCheck(this, Meets);
_this2 = _super2.call(this, json);
_this2.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this2;
}
_createClass(Meets, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs = this.execArgs(ctx),
_this$execArgs2 = _slicedToArray(_this$execArgs, 2),
a = _this$execArgs2[0],
b = _this$execArgs2[1];
if (a != null && b != null) {
return a.meets(b, this.precision);
} else {
return null;
}
}
}]);
return Meets;
}(Expression);
var MeetsAfter = /*#__PURE__*/function (_Expression3) {
_inherits(MeetsAfter, _Expression3);
var _super3 = _createSuper(MeetsAfter);
function MeetsAfter(json) {
var _this3;
_classCallCheck(this, MeetsAfter);
_this3 = _super3.call(this, json);
_this3.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this3;
}
_createClass(MeetsAfter, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs3 = this.execArgs(ctx),
_this$execArgs4 = _slicedToArray(_this$execArgs3, 2),
a = _this$execArgs4[0],
b = _this$execArgs4[1];
if (a != null && b != null) {
return a.meetsAfter(b, this.precision);
} else {
return null;
}
}
}]);
return MeetsAfter;
}(Expression);
var MeetsBefore = /*#__PURE__*/function (_Expression4) {
_inherits(MeetsBefore, _Expression4);
var _super4 = _createSuper(MeetsBefore);
function MeetsBefore(json) {
var _this4;
_classCallCheck(this, MeetsBefore);
_this4 = _super4.call(this, json);
_this4.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this4;
}
_createClass(MeetsBefore, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs5 = this.execArgs(ctx),
_this$execArgs6 = _slicedToArray(_this$execArgs5, 2),
a = _this$execArgs6[0],
b = _this$execArgs6[1];
if (a != null && b != null) {
return a.meetsBefore(b, this.precision);
} else {
return null;
}
}
}]);
return MeetsBefore;
}(Expression);
var Overlaps = /*#__PURE__*/function (_Expression5) {
_inherits(Overlaps, _Expression5);
var _super5 = _createSuper(Overlaps);
function Overlaps(json) {
var _this5;
_classCallCheck(this, Overlaps);
_this5 = _super5.call(this, json);
_this5.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this5;
}
_createClass(Overlaps, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs7 = this.execArgs(ctx),
_this$execArgs8 = _slicedToArray(_this$execArgs7, 2),
a = _this$execArgs8[0],
b = _this$execArgs8[1];
if (a != null && b != null) {
return a.overlaps(b, this.precision);
} else {
return null;
}
}
}]);
return Overlaps;
}(Expression);
var OverlapsAfter = /*#__PURE__*/function (_Expression6) {
_inherits(OverlapsAfter, _Expression6);
var _super6 = _createSuper(OverlapsAfter);
function OverlapsAfter(json) {
var _this6;
_classCallCheck(this, OverlapsAfter);
_this6 = _super6.call(this, json);
_this6.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this6;
}
_createClass(OverlapsAfter, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs9 = this.execArgs(ctx),
_this$execArgs10 = _slicedToArray(_this$execArgs9, 2),
a = _this$execArgs10[0],
b = _this$execArgs10[1];
if (a != null && b != null) {
return a.overlapsAfter(b, this.precision);
} else {
return null;
}
}
}]);
return OverlapsAfter;
}(Expression);
var OverlapsBefore = /*#__PURE__*/function (_Expression7) {
_inherits(OverlapsBefore, _Expression7);
var _super7 = _createSuper(OverlapsBefore);
function OverlapsBefore(json) {
var _this7;
_classCallCheck(this, OverlapsBefore);
_this7 = _super7.call(this, json);
_this7.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this7;
}
_createClass(OverlapsBefore, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs11 = this.execArgs(ctx),
_this$execArgs12 = _slicedToArray(_this$execArgs11, 2),
a = _this$execArgs12[0],
b = _this$execArgs12[1];
if (a != null && b != null) {
return a.overlapsBefore(b, this.precision);
} else {
return null;
}
}
}]);
return OverlapsBefore;
}(Expression); // Delegated to by overloaded#Union
function doUnion(a, b) {
return a.union(b);
} // Delegated to by overloaded#Except
function doExcept(a, b) {
if (a != null && b != null) {
return a.except(b);
} else {
return null;
}
} // Delegated to by overloaded#Intersect
function doIntersect(a, b) {
if (a != null && b != null) {
return a.intersect(b);
} else {
return null;
}
}
var Width = /*#__PURE__*/function (_Expression8) {
_inherits(Width, _Expression8);
var _super8 = _createSuper(Width);
function Width(json) {
_classCallCheck(this, Width);
return _super8.call(this, json);
}
_createClass(Width, [{
key: "exec",
value: function exec(ctx) {
var interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
return interval.width();
}
}]);
return Width;
}(Expression);
var Size = /*#__PURE__*/function (_Expression9) {
_inherits(Size, _Expression9);
var _super9 = _createSuper(Size);
function Size(json) {
_classCallCheck(this, Size);
return _super9.call(this, json);
}
_createClass(Size, [{
key: "exec",
value: function exec(ctx) {
var interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
return interval.size();
}
}]);
return Size;
}(Expression);
var Start = /*#__PURE__*/function (_Expression10) {
_inherits(Start, _Expression10);
var _super10 = _createSuper(Start);
function Start(json) {
_classCallCheck(this, Start);
return _super10.call(this, json);
}
_createClass(Start, [{
key: "exec",
value: function exec(ctx) {
var interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
var start = interval.start(); // fix the timezoneOffset of minimum Datetime to match context offset
if (start && start.isDateTime && start.equals(MIN_DATETIME_VALUE)) {
start.timezoneOffset = ctx.getTimezoneOffset();
}
return start;
}
}]);
return Start;
}(Expression);
var End = /*#__PURE__*/function (_Expression11) {
_inherits(End, _Expression11);
var _super11 = _createSuper(End);
function End(json) {
_classCallCheck(this, End);
return _super11.call(this, json);
}
_createClass(End, [{
key: "exec",
value: function exec(ctx) {
var interval = this.arg.execute(ctx);
if (interval == null) {
return null;
}
var end = interval.end(); // fix the timezoneOffset of maximum Datetime to match context offset
if (end && end.isDateTime && end.equals(MAX_DATETIME_VALUE)) {
end.timezoneOffset = ctx.getTimezoneOffset();
}
return end;
}
}]);
return End;
}(Expression);
var Starts = /*#__PURE__*/function (_Expression12) {
_inherits(Starts, _Expression12);
var _super12 = _createSuper(Starts);
function Starts(json) {
var _this8;
_classCallCheck(this, Starts);
_this8 = _super12.call(this, json);
_this8.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this8;
}
_createClass(Starts, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs13 = this.execArgs(ctx),
_this$execArgs14 = _slicedToArray(_this$execArgs13, 2),
a = _this$execArgs14[0],
b = _this$execArgs14[1];
if (a != null && b != null) {
return a.starts(b, this.precision);
} else {
return null;
}
}
}]);
return Starts;
}(Expression);
var Ends = /*#__PURE__*/function (_Expression13) {
_inherits(Ends, _Expression13);
var _super13 = _createSuper(Ends);
function Ends(json) {
var _this9;
_classCallCheck(this, Ends);
_this9 = _super13.call(this, json);
_this9.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
return _this9;
}
_createClass(Ends, [{
key: "exec",
value: function exec(ctx) {
var _this$execArgs15 = this.execArgs(ctx),
_this$execArgs16 = _slicedToArray(_this$execArgs15, 2),
a = _this$execArgs16[0],
b = _this$execArgs16[1];
if (a != null && b != null) {
return a.ends(b, this.precision);
} else {
return null;
}
}
}]);
return Ends;
}(Expression);
function intervalListType(intervals) {
// Returns one of null, 'time', 'date', 'datetime', 'quantity', 'integer', 'decimal' or 'mismatch'
var type = null;
var _iterator = _createForOfIteratorHelper(intervals),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var itvl = _step.value;
if (itvl == null) {
continue;
}
if (itvl.low == null && itvl.high == null) {
//can't really determine type from this
continue;
} // if one end is null (but not both), the type can be determined from the other end
var low = itvl.low != null ? itvl.low : itvl.high;
var high = itvl.high != null ? itvl.high : itvl.low;
if (low.isTime && low.isTime() && high.isTime && high.isTime()) {
if (type == null) {
type = 'time';
} else if (type === 'time') {
continue;
} else {
return 'mismatch';
} // if an interval mixes date and datetime, type is datetime (for implicit conversion)
} 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' || type === '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' || type === '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';
} //if we are here ends are mismatched
} else {
return 'mismatch';
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return type;
}
var Expand = /*#__PURE__*/function (_Expression14) {
_inherits(Expand, _Expression14);
var _super14 = _createSuper(Expand);
function Expand(json) {
_classCallCheck(this, Expand);
return _super14.call(this, json);
}
_createClass(Expand, [{
key: "exec",
value: function exec(ctx) {
// expand(argument List<Interval<T>>, per Quantity) List<Interval<T>>
var defaultPer, expandFunction;
var _this$execArgs17 = this.execArgs(ctx),
_this$execArgs18 = _slicedToArray(_this$execArgs17, 2),
intervals = _this$execArgs18[0],
per = _this$execArgs18[1]; // CQL 1.5 introduced an overload to allow singular intervals; make it a list so we can use the same logic for either overload
if (!Array.isArray(intervals)) {
intervals = [intervals];
}
var type = intervalListType(intervals);
if (type === 'mismatch') {
throw new Error('List of intervals contains mismatched types.');
}
if (type == null) {
return null;
} // this step collapses overlaps, and also returns a clone of intervals so we can feel free to mutate
intervals = collapseIntervals(intervals, per);
if (intervals.length === 0) {
return [];
}
if (['time', 'date', 'datetime'].includes(type)) {
expandFunction = this.expandDTishInterval;
defaultPer = function defaultPer(interval) {
return new Quantity(1, interval.low.getPrecision());
};
} else if (['quantity'].includes(type)) {
expandFunction = this.expandQuantityInterval;
defaultPer = function defaultPer(interval) {
return new Quantity(1, interval.low.unit);
};
} else if (['integer', 'decimal'].includes(type)) {
expandFunction = this.expandNumericInterval;
defaultPer = function defaultPer(interval) {
return new Quantity(1, '1');
};
} else {
throw new Error('Interval list type not yet supported.');
}
var results = [];
var _iterator2 = _createForOfIteratorHelper(intervals),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var interval = _step2.value;
if (interval == null) {
continue;
} // We do not support open ended intervals since result would likely be too long
if (interval.low == null || interval.high == null) {
return null;
}
if (type === 'datetime') {
//support for implicitly converting dates to datetime
interval.low = interval.low.getDateTime();
interval.high = interval.high.getDateTime();
}
per = per != null ? per : defaultPer(interval);
var items = expandFunction.call(this, interval, per);
if (items === null) {
return null;
}
results.push.apply(results, _toConsumableArray(items || []));
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return results;
}
}, {
key: "expandDTishInterval",
value: function expandDTishInterval(interval, per) {
per.unit = convertToCQLDateUnit(per.unit);
if (per.unit === 'week') {
per.value *= 7;
per.unit = 'day';
} // Precision Checks
// return null if precision not applicable (e.g. gram, or minutes for dates)
if (!interval.low.constructor.FIELDS.includes(per.unit)) {
return null;
} // open interval with null boundaries do not contribute to output
// closed interval with null boundaries are not allowed for performance reasons
if (interval.low == null || interval.high == null) {
return null;
}
var low = interval.lowClosed ? interval.low : interval.low.successor();
var high = interval.highClosed ? interval.high : interval.high.predecessor();
if (low.after(high)) {
return [];
}
if (interval.low.isLessPrecise(per.unit) || interval.high.isLessPrecise(per.unit)) {
return [];
}
var current_low = low;
var results = [];
low = this.truncateToPrecision(low, per.unit);
high = this.truncateToPrecision(high, per.unit);
var current_high = current_low.add(per.value, per.unit).predecessor();
var intervalToAdd = new dtivl.Interval(current_low, current_high, true, true);
while (intervalToAdd.high.sameOrBefore(high)) {
results.push(intervalToAdd);
current_low = current_low.add(per.value, per.unit);
current_high = current_low.add(per.value, per.unit).predecessor();
intervalToAdd = new dtivl.Interval(current_low, current_high, true, true);
}
return results;
}
}, {
key: "truncateToPrecision",
value: function truncateToPrecision(value, unit) {
// If interval boundaries are more precise than per quantity, truncate to
// the precision specified by the per
var shouldTruncate = false;
var _iterator3 = _createForOfIteratorHelper(value.constructor.FIELDS),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var field = _step3.value;
if (shouldTruncate) {
value[field] = null;
}
if (field === unit) {
// Start truncating after this unit
shouldTruncate = true;
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return value;
}
}, {
key: "expandQuantityInterval",
value: function expandQuantityInterval(interval, per) {
// we want to convert everything to the more precise of the interval.low or per
var result_units;
if (compareUnits(interval.low.unit, per.unit) > 0) {
//interval.low.unit is 'bigger' aka les precise
result_units = per.unit;
} else {
result_units = interval.low.unit;
}
var low_value = convertUnit(interval.low.value, interval.low.unit, result_units);
var high_value = convertUnit(interval.high.value, interval.high.unit, result_units);
var per_value = convertUnit(per.value, per.unit, result_units); // return null if unit conversion failed, must have mismatched units
if (!(low_value != null && high_value != null && per_value != null)) {
return null;
}
var results = this.makeNumericIntervalList(low_value, high_value, interval.lowClosed, interval.highClosed, per_value);
var _iterator4 = _createForOfIteratorHelper(results),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var itvl = _step4.value;
itvl.low = new Quantity(itvl.low, result_units);
itvl.high = new Quantity(itvl.high, result_units);
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return results;
}
}, {
key: "expandNumericInterval",
value: function expandNumericInterval(interval, per) {
if (per.unit !== '1' && per.unit !== '') {
return null;
}
return this.makeNumericIntervalList(interval.low, interval.high, interval.lowClosed, interval.highClosed, per.value);
}
}, {
key: "makeNumericIntervalList",
value: function makeNumericIntervalList(low, high, lowClosed, highClosed, perValue) {
// If the per value is a Decimal (has a .), 8 decimal places are appropriate
// Integers should have 0 Decimal places
var perIsDecimal = perValue.toString().includes('.');
var decimalPrecision = perIsDecimal ? 8 : 0;
low = lowClosed ? low : successor(low);
high = highClosed ? high : predecessor(high); // If the interval boundaries are more precise than the per quantity, the
// more precise values will be truncated to the precision specified by the
// per quantity.
low = truncateDecimal(low, decimalPrecision);
high = truncateDecimal(high, decimalPrecision);
if (low > high) {
return [];
}
if (low == null || high == null) {
return [];
}
var perUnitSize = perIsDecimal ? 0.00000001 : 1;
if (low === high && Number.isInteger(low) && Number.isInteger(high) && !Number.isInteger(perValue)) {
high = parseFloat((high + 1).toFixed(decimalPrecision));
}
var current_low = low;
var results = [];
if (perValue > high - low + perUnitSize) {
return [];
}
var current_high = parseFloat((current_low + perValue - perUnitSize).toFixed(decimalPrecision));
var intervalToAdd = new dtivl.Interval(current_low, current_high, true, true);
while (intervalToAdd.high <= high) {
results.push(intervalToAdd);
current_low = parseFloat((current_low + perValue).toFixed(decimalPrecision));
current_high = parseFloat((current_low + perValue - perUnitSize).toFixed(decimalPrecision));
intervalToAdd = new dtivl.Interval(current_low, current_high, true, true);
}
return results;
}
}]);
return Expand;
}(Expression);
var Collapse = /*#__PURE__*/function (_Expression15) {
_inherits(Collapse, _Expression15);
var _super15 = _createSuper(Collapse);
function Collapse(json) {
_classCallCheck(this, Collapse);
return _super15.call(this, json);
}
_createClass(Collapse, [{
key: "exec",
value: function exec(ctx) {
// collapse(argument List<Interval<T>>, per Quantity) List<Interval<T>>
var _this$execArgs19 = this.execArgs(ctx),
_this$execArgs20 = _slicedToArray(_this$execArgs19, 2),
intervals = _this$execArgs20[0],
perWidth = _this$execArgs20[1];
return collapseIntervals(intervals, perWidth);
}
}]);
return Collapse;
}(Expression);
function collapseIntervals(intervals, perWidth) {
// Clone intervals so this function remains idempotent
var intervalsClone = [];
var _iterator5 = _createForOfIteratorHelper(intervals),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var interval = _step5.value;
// The spec says to ignore null intervals
if (interval != null) {
intervalsClone.push(interval.copy());
}
} // If the list is null, return null
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
if (intervals == null) {
return null;
} else if (intervalsClone.length <= 1) {
return intervalsClone;
} else {
// If the per argument is null, the default unit interval for the point type
// of the intervals involved will be used (i.e. the interval that has a
// width equal to the result of the successor function for the point type).
if (perWidth == null) {
perWidth = intervalsClone[0].getPointSize();
} // sort intervalsClone by start
intervalsClone.sort(function (a, b) {
if (a.low && typeof a.low.before === '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 both lows are undefined, sort by high
if (a.high && typeof a.high.before === '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;
}); // collapse intervals as necessary
var collapsedIntervals = [];
var a = intervalsClone.shift();
var b = intervalsClone.shift();
while (b) {
if (b.low && typeof b.low.durationBetween === 'function') {
// handle DateTimes using durationBetween
if (a.high != null ? a.high.sameOrAfter(b.low) : undefined) {
// overlap
if (b.high == null || b.high.after(a.high)) {
a.high = b.high;
}
} else if ((a.high != null ? a.high.durationBetween(b.low, perWidth.unit).high : undefined) <= perWidth.value) {
a.high = b.high;
} else {
collapsedIntervals.push(a);
a = b;
}
} else if (b.low && typeof b.low.sameOrBefore === '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;
}
}
function truncateDecimal(decimal, decimalPlaces) {
// like parseFloat().toFixed() but floor rather than round
// Needed for when per precision is less than the interval input precision
var re = new RegExp('^-?\\d+(?:.\\d{0,' + (decimalPlaces || -1) + '})?');
return parseFloat(decimal.toString().match(re)[0]);
}
module.exports = {
Collapse: Collapse,
End: End,
Ends: Ends,
Expand: Expand,
Interval: Interval,
Meets: Meets,
MeetsAfter: MeetsAfter,
MeetsBefore: MeetsBefore,
Overlaps: Overlaps,
OverlapsAfter: OverlapsAfter,
OverlapsBefore: OverlapsBefore,
Size: Size,
Start: Start,
Starts: Starts,
Width: Width,
doContains: doContains,
doIncludes: doIncludes,
doProperIncludes: doProperIncludes,
doAfter: doAfter,
doBefore: doBefore,
doUnion: doUnion,
doExcept: doExcept,
doIntersect: doIntersect
};