UNPKG

@phema/cql-execution

Version:

An execution framework for the Clinical Quality Language (CQL)

1,129 lines (872 loc) 35.7 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 _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 };