aggregate_calculator.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * DevExtreme (ui/data_grid/aggregate_calculator.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _class = require("../../core/class");
  11. var _class2 = _interopRequireDefault(_class);
  12. var _data = require("../../core/utils/data");
  13. var _type = require("../../core/utils/type");
  14. var _errors = require("../../data/errors");
  15. var _utils = require("../../data/utils");
  16. function _interopRequireDefault(obj) {
  17. return obj && obj.__esModule ? obj : {
  18. "default": obj
  19. }
  20. }
  21. function depthFirstSearch(i, depth, root, callback) {
  22. var j = 0;
  23. if (i < depth) {
  24. for (; j < root.items.length; j++) {
  25. depthFirstSearch(i + 1, depth, root.items[j], callback)
  26. }
  27. }
  28. if (i === depth) {
  29. callback(root)
  30. }
  31. }
  32. function map(array, callback) {
  33. if ("map" in array) {
  34. return array.map(callback)
  35. }
  36. var result = new Array(array.length);
  37. for (var i in array) {
  38. result[i] = callback(array[i], i)
  39. }
  40. return result
  41. }
  42. function isEmpty(x) {
  43. return x !== x || "" === x || null === x || void 0 === x
  44. }
  45. function isCount(aggregator) {
  46. return aggregator === _utils.aggregators.count
  47. }
  48. function normalizeAggregate(aggregate) {
  49. var selector = (0, _data.compileGetter)(aggregate.selector);
  50. var skipEmptyValues = "skipEmptyValues" in aggregate ? aggregate.skipEmptyValues : true;
  51. var aggregator = aggregate.aggregator;
  52. if ("string" === typeof aggregator) {
  53. aggregator = _utils.aggregators[aggregator];
  54. if (!aggregator) {
  55. throw _errors.errors.Error("E4001", aggregate.aggregator)
  56. }
  57. }
  58. return {
  59. selector: selector,
  60. aggregator: aggregator,
  61. skipEmptyValues: skipEmptyValues
  62. }
  63. }
  64. module.exports = _class2.default.inherit({
  65. ctor: function(options) {
  66. this._data = options.data;
  67. this._groupLevel = options.groupLevel || 0;
  68. this._totalAggregates = map(options.totalAggregates || [], normalizeAggregate);
  69. this._groupAggregates = map(options.groupAggregates || [], normalizeAggregate);
  70. this._totals = []
  71. },
  72. calculate: function() {
  73. if (this._totalAggregates.length) {
  74. this._calculateTotals(0, {
  75. items: this._data
  76. })
  77. }
  78. if (this._groupAggregates.length && this._groupLevel > 0) {
  79. this._calculateGroups({
  80. items: this._data
  81. })
  82. }
  83. },
  84. totalAggregates: function() {
  85. return this._totals
  86. },
  87. _aggregate: function(aggregates, data, container) {
  88. var length = data.items ? data.items.length : 0;
  89. for (var i = 0; i < aggregates.length; i++) {
  90. if (isCount(aggregates[i].aggregator)) {
  91. container[i] = (container[i] || 0) + length;
  92. continue
  93. }
  94. for (var j = 0; j < length; j++) {
  95. this._accumulate(i, aggregates[i], container, data.items[j])
  96. }
  97. }
  98. },
  99. _calculateTotals: function(level, data) {
  100. if (0 === level) {
  101. this._totals = this._seed(this._totalAggregates)
  102. }
  103. if (level === this._groupLevel) {
  104. this._aggregate(this._totalAggregates, data, this._totals)
  105. } else {
  106. for (var i = 0; i < data.items.length; i++) {
  107. this._calculateTotals(level + 1, data.items[i])
  108. }
  109. }
  110. if (0 === level) {
  111. this._totals = this._finalize(this._totalAggregates, this._totals)
  112. }
  113. },
  114. _calculateGroups: function(root) {
  115. var maxLevel = this._groupLevel;
  116. var currentLevel = maxLevel + 1;
  117. var seedFn = this._seed.bind(this, this._groupAggregates);
  118. var stepFn = this._aggregate.bind(this, this._groupAggregates);
  119. var finalizeFn = this._finalize.bind(this, this._groupAggregates);
  120. function aggregator(node) {
  121. node.aggregates = seedFn(currentLevel - 1);
  122. if (currentLevel === maxLevel) {
  123. stepFn(node, node.aggregates)
  124. } else {
  125. depthFirstSearch(currentLevel, maxLevel, node, function(innerNode) {
  126. stepFn(innerNode, node.aggregates)
  127. })
  128. }
  129. node.aggregates = finalizeFn(node.aggregates)
  130. }
  131. while (--currentLevel > 0) {
  132. depthFirstSearch(0, currentLevel, root, aggregator)
  133. }
  134. },
  135. _seed: function(aggregates, groupIndex) {
  136. return map(aggregates, function(aggregate) {
  137. var aggregator = aggregate.aggregator;
  138. var seed = "seed" in aggregator ? (0, _type.isFunction)(aggregator.seed) ? aggregator.seed(groupIndex) : aggregator.seed : NaN;
  139. return seed
  140. })
  141. },
  142. _accumulate: function(aggregateIndex, aggregate, results, item) {
  143. var value = aggregate.selector(item);
  144. var aggregator = aggregate.aggregator;
  145. var skipEmptyValues = aggregate.skipEmptyValues;
  146. if (skipEmptyValues && isEmpty(value)) {
  147. return
  148. }
  149. if (results[aggregateIndex] !== results[aggregateIndex]) {
  150. results[aggregateIndex] = value
  151. } else {
  152. results[aggregateIndex] = aggregator.step(results[aggregateIndex], value)
  153. }
  154. },
  155. _finalize: function(aggregates, results) {
  156. return map(aggregates, function(aggregate, index) {
  157. var fin = aggregate.aggregator.finalize;
  158. return fin ? fin(results[index]) : results[index]
  159. })
  160. }
  161. });