UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

168 lines (161 loc) 5.71 kB
/** * DevExtreme (esm/ui/data_grid/aggregate_calculator.js) * Version: 21.1.4 * Build date: Mon Jun 21 2021 * * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import Class from "../../core/class"; import { compileGetter } from "../../core/utils/data"; import { isFunction } from "../../core/utils/type"; import { errors } from "../../data/errors"; import dataUtils from "../../data/utils"; function depthFirstSearch(i, depth, root, callback) { var j = 0; if (i < depth) { for (; j < root.items.length; j++) { depthFirstSearch(i + 1, depth, root.items[j], callback) } } if (i === depth) { callback(root) } } function map(array, callback) { var i; if ("map" in array) { return array.map(callback) } var result = new Array(array.length); for (i in array) { result[i] = callback(array[i], i) } return result } function isEmpty(x) { return x !== x || "" === x || null === x || void 0 === x } function isCount(aggregator) { return aggregator === dataUtils.aggregators.count } function normalizeAggregate(aggregate) { var selector = compileGetter(aggregate.selector); var skipEmptyValues = "skipEmptyValues" in aggregate ? aggregate.skipEmptyValues : true; var aggregator = aggregate.aggregator; if ("string" === typeof aggregator) { aggregator = dataUtils.aggregators[aggregator]; if (!aggregator) { throw errors.Error("E4001", aggregate.aggregator) } } return { selector: selector, aggregator: aggregator, skipEmptyValues: skipEmptyValues } } export default Class.inherit({ ctor: function(options) { this._data = options.data; this._groupLevel = options.groupLevel || 0; this._totalAggregates = map(options.totalAggregates || [], normalizeAggregate); this._groupAggregates = map(options.groupAggregates || [], normalizeAggregate); this._totals = [] }, calculate: function() { if (this._totalAggregates.length) { this._calculateTotals(0, { items: this._data }) } if (this._groupAggregates.length && this._groupLevel > 0) { this._calculateGroups({ items: this._data }) } }, totalAggregates: function() { return this._totals }, _aggregate: function(aggregates, data, container) { var length = data.items ? data.items.length : 0; for (var i = 0; i < aggregates.length; i++) { if (isCount(aggregates[i].aggregator)) { container[i] = (container[i] || 0) + length; continue } for (var j = 0; j < length; j++) { this._accumulate(i, aggregates[i], container, data.items[j]) } } }, _calculateTotals: function(level, data) { if (0 === level) { this._totals = this._seed(this._totalAggregates) } if (level === this._groupLevel) { this._aggregate(this._totalAggregates, data, this._totals) } else { for (var i = 0; i < data.items.length; i++) { this._calculateTotals(level + 1, data.items[i]) } } if (0 === level) { this._totals = this._finalize(this._totalAggregates, this._totals) } }, _calculateGroups: function(root) { var maxLevel = this._groupLevel; var currentLevel = maxLevel + 1; var seedFn = this._seed.bind(this, this._groupAggregates); var stepFn = this._aggregate.bind(this, this._groupAggregates); var finalizeFn = this._finalize.bind(this, this._groupAggregates); function aggregator(node) { node.aggregates = seedFn(currentLevel - 1); if (currentLevel === maxLevel) { stepFn(node, node.aggregates) } else { depthFirstSearch(currentLevel, maxLevel, node, (function(innerNode) { stepFn(innerNode, node.aggregates) })) } node.aggregates = finalizeFn(node.aggregates) } while (--currentLevel > 0) { depthFirstSearch(0, currentLevel, root, aggregator) } }, _seed: function(aggregates, groupIndex) { return map(aggregates, (function(aggregate) { var aggregator = aggregate.aggregator; var seed = "seed" in aggregator ? isFunction(aggregator.seed) ? aggregator.seed(groupIndex) : aggregator.seed : NaN; return seed })) }, _accumulate: function(aggregateIndex, aggregate, results, item) { var value = aggregate.selector(item); var aggregator = aggregate.aggregator; var skipEmptyValues = aggregate.skipEmptyValues; if (skipEmptyValues && isEmpty(value)) { return } if (results[aggregateIndex] !== results[aggregateIndex]) { results[aggregateIndex] = value } else { results[aggregateIndex] = aggregator.step(results[aggregateIndex], value) } }, _finalize: function(aggregates, results) { return map(aggregates, (function(aggregate, index) { var fin = aggregate.aggregator.finalize; return fin ? fin(results[index]) : results[index] })) } });