UNPKG

mingo

Version:

MongoDB query language for in-memory objects

178 lines (177 loc) 7.28 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var densify_exports = {}; __export(densify_exports, { $densify: () => $densify }); module.exports = __toCommonJS(densify_exports); var import_lazy = require("../../lazy"); var import_util = require("../../util"); var import_internal = require("../expression/date/_internal"); var import_dateAdd = require("../expression/date/dateAdd"); var import_sort = require("./sort"); const $densify = (collection, expr, options) => { const { step, bounds, unit } = expr.range; if (unit) { (0, import_util.assert)(import_internal.TIME_UNITS.includes(unit), ""); (0, import_util.assert)( Number.isInteger(step) && step > 0, "The step parameter in a range statement must be a whole number when densifying a date range." ); } else { (0, import_util.assert)( (0, import_util.isNumber)(step) && step > 0, "The step parameter in a range statement must be a strictly positive numeric value." ); } if ((0, import_util.isArray)(bounds)) { (0, import_util.assert)( !!bounds && bounds.length === 2, "A bounding array in a range statement must have exactly two elements." ); (0, import_util.assert)( (bounds.every(import_util.isNumber) || bounds.every(import_util.isDate)) && bounds[0] < bounds[1], "A bounding array must be an ascending array of either two dates or two numbers." ); (0, import_util.assert)( unit && !bounds.some(import_util.isNumber), "Numeric bounds may not have unit parameter." ); } if (expr.partitionByFields) { (0, import_util.assert)( (0, import_util.isArray)(expr.partitionByFields), "$densify: `partitionByFields` must be an array of strings" ); } collection = (0, import_sort.$sort)(collection, { [expr.field]: 1 }, options); const computeNextValue = (value) => { return (0, import_util.isNumber)(value) ? value + step : (0, import_dateAdd.$dateAdd)(null, { startDate: value, unit, amount: step }, options); }; const isValidUnit = !!unit && import_internal.TIME_UNITS.includes(unit); const getFieldValue = (o) => { const v = (0, import_util.resolve)(o, expr.field); (0, import_util.assert)( (0, import_util.isNil)(v) || (0, import_util.isDate)(v) && isValidUnit || (0, import_util.isNumber)(v) && !isValidUnit, "$densify: Densify field type must be numeric with 'unit' unspecified, or a date with 'unit' specified." ); return v; }; const peekItem = new Array(); const nilFieldsIterator = (0, import_lazy.Lazy)(() => { const item = collection.next(); const fieldValue = getFieldValue(item.value); if ((0, import_util.isNil)(fieldValue)) return item; peekItem.push(item); return { done: true }; }); const nextDensifyValueMap = import_util.HashMap.init(); const [lower, upper] = (0, import_util.isArray)(bounds) ? bounds : [bounds, bounds]; let maxFieldValue = void 0; const updateMaxFieldValue = (value) => { maxFieldValue = maxFieldValue === void 0 || maxFieldValue < value ? value : maxFieldValue; }; const rootKey = []; const densifyIterator = (0, import_lazy.Lazy)(() => { const item = peekItem.length > 0 ? peekItem.pop() : collection.next(); if (item.done) return item; let partitionKey = rootKey; if ((0, import_util.isArray)(expr.partitionByFields)) { partitionKey = expr.partitionByFields.map( (k) => (0, import_util.resolve)(item.value, k) ); (0, import_util.assert)( partitionKey.every(import_util.isString), "$densify: Partition fields must evaluate to string values." ); } (0, import_util.assert)((0, import_util.isObject)(item.value), "$densify: collection must contain documents"); const itemValue = getFieldValue(item.value); if (!nextDensifyValueMap.has(partitionKey)) { if (lower == "full") { if (!nextDensifyValueMap.has(rootKey)) { nextDensifyValueMap.set(rootKey, itemValue); } nextDensifyValueMap.set(partitionKey, nextDensifyValueMap.get(rootKey)); } else if (lower == "partition") { nextDensifyValueMap.set(partitionKey, itemValue); } else { nextDensifyValueMap.set(partitionKey, lower); } } const densifyValue = nextDensifyValueMap.get(partitionKey); if ( // current item field value is lower than current densify value. itemValue <= densifyValue || // range value equals or exceeds upper bound upper != "full" && upper != "partition" && densifyValue >= upper ) { if (densifyValue <= itemValue) { nextDensifyValueMap.set(partitionKey, computeNextValue(densifyValue)); } updateMaxFieldValue(itemValue); return item; } nextDensifyValueMap.set(partitionKey, computeNextValue(densifyValue)); updateMaxFieldValue(densifyValue); const denseObj = { [expr.field]: densifyValue }; if (partitionKey) { partitionKey.forEach((v, i) => { denseObj[expr.partitionByFields[i]] = v; }); } peekItem.push(item); return { done: false, value: denseObj }; }); if (lower !== "full") return (0, import_lazy.concat)(nilFieldsIterator, densifyIterator); let paritionIndex = -1; let partitionKeysSet = void 0; const fullBoundsIterator = (0, import_lazy.Lazy)(() => { if (paritionIndex === -1) { const fullDensifyValue = nextDensifyValueMap.get(rootKey); nextDensifyValueMap.delete(rootKey); partitionKeysSet = Array.from(nextDensifyValueMap.keys()); if (partitionKeysSet.length === 0) { partitionKeysSet.push(rootKey); nextDensifyValueMap.set(rootKey, fullDensifyValue); } paritionIndex++; } do { const partitionKey = partitionKeysSet[paritionIndex]; const partitionMaxValue = nextDensifyValueMap.get(partitionKey); if (partitionMaxValue < maxFieldValue) { nextDensifyValueMap.set( partitionKey, computeNextValue(partitionMaxValue) ); const denseObj = { [expr.field]: partitionMaxValue }; partitionKey.forEach((v, i) => { denseObj[expr.partitionByFields[i]] = v; }); return { done: false, value: denseObj }; } paritionIndex++; } while (paritionIndex < partitionKeysSet.length); return { done: true }; }); return (0, import_lazy.concat)(nilFieldsIterator, densifyIterator, fullBoundsIterator); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { $densify });