local_store.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /**
  2. * DevExtreme (ui/pivot_grid/local_store.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 _deferred = require("../../core/utils/deferred");
  11. var _utils = require("../../data/utils");
  12. var _query = require("../../data/query");
  13. var _query2 = _interopRequireDefault(_query);
  14. var _date_serialization = require("../../core/utils/date_serialization");
  15. var _data_source = require("../../data/data_source/data_source");
  16. var _custom_store = require("../../data/custom_store");
  17. var _custom_store2 = _interopRequireDefault(_custom_store);
  18. var _data = require("../../core/utils/data");
  19. var _class = require("../../core/class");
  20. var _class2 = _interopRequireDefault(_class);
  21. var _common = require("../../core/utils/common");
  22. var _type = require("../../core/utils/type");
  23. var _iterator = require("../../core/utils/iterator");
  24. var _uiPivot_grid = require("./ui.pivot_grid.utils");
  25. var _array_store = require("../../data/array_store");
  26. var _array_store2 = _interopRequireDefault(_array_store);
  27. function _interopRequireDefault(obj) {
  28. return obj && obj.__esModule ? obj : {
  29. "default": obj
  30. }
  31. }
  32. var PATH_DELIMETER = "/./";
  33. exports.LocalStore = _class2.default.inherit(function() {
  34. var DATE_INTERVAL_SELECTORS = {
  35. year: function(date) {
  36. return date && date.getFullYear()
  37. },
  38. quarter: function(date) {
  39. return date && Math.floor(date.getMonth() / 3) + 1
  40. },
  41. month: function(date) {
  42. return date && date.getMonth() + 1
  43. },
  44. day: function(date) {
  45. return date && date.getDate()
  46. },
  47. dayOfWeek: function(date) {
  48. return date && date.getDay()
  49. }
  50. };
  51. function getDataSelector(dataField) {
  52. return dataField.indexOf(".") !== -1 ? (0, _data.compileGetter)(dataField) : function(data) {
  53. return data[dataField]
  54. }
  55. }
  56. function getDateValue(dataSelector) {
  57. return function(data) {
  58. var value = dataSelector(data);
  59. if (value && !(value instanceof Date)) {
  60. value = (0, _date_serialization.deserializeDate)(value)
  61. }
  62. return value
  63. }
  64. }
  65. function prepareFields(fields) {
  66. (0, _iterator.each)(fields || [], function(_, field) {
  67. var fieldSelector;
  68. var dataField = field.dataField;
  69. var levels = field.levels;
  70. var dataSelector;
  71. if (!field.selector) {
  72. if (!dataField) {
  73. dataSelector = function(data) {
  74. return data
  75. }
  76. } else {
  77. dataSelector = getDataSelector(dataField)
  78. }
  79. if (levels) {
  80. prepareFields(levels)
  81. }
  82. if ("date" === field.dataType) {
  83. var intervalSelector = DATE_INTERVAL_SELECTORS[field.groupInterval];
  84. var valueSelector = getDateValue(dataSelector);
  85. fieldSelector = function(data) {
  86. var value = valueSelector(data);
  87. return intervalSelector ? intervalSelector(value) : value
  88. }
  89. } else {
  90. if ("number" === field.dataType) {
  91. var groupInterval = (0, _type.isNumeric)(field.groupInterval) && field.groupInterval > 0 && field.groupInterval;
  92. fieldSelector = function(data) {
  93. var value = dataSelector(data);
  94. if ((0, _type.isString)(value)) {
  95. value = Number(value)
  96. }
  97. return groupInterval ? Math.floor(value / groupInterval) * groupInterval : value
  98. }
  99. } else {
  100. fieldSelector = dataSelector
  101. }
  102. }(0, _uiPivot_grid.setDefaultFieldValueFormatting)(field);
  103. (0, _uiPivot_grid.setFieldProperty)(field, "selector", fieldSelector)
  104. }
  105. })
  106. }
  107. var addHierarchyItem = function(value, hierarchyItems, pathHash, childrenHash) {
  108. var hierarchyItem = childrenHash[pathHash];
  109. if (!hierarchyItem) {
  110. hierarchyItem = {
  111. value: value,
  112. index: childrenHash.length++
  113. };
  114. childrenHash[pathHash] = hierarchyItem;
  115. hierarchyItems.push(hierarchyItem)
  116. }
  117. return hierarchyItem
  118. };
  119. function fillHierarchyItemIndexesCore(indexes, options, children, expandIndex, pathHash) {
  120. var dimension = options.dimensions[expandIndex];
  121. var expandedPathsHash = options.expandedPathsHash;
  122. if (dimension) {
  123. var dimensionValue = dimension.selector(options.data);
  124. pathHash = void 0 !== pathHash ? pathHash + PATH_DELIMETER + dimensionValue : dimensionValue + "";
  125. var hierarchyItem = addHierarchyItem(dimensionValue, children, pathHash, options.childrenHash);
  126. indexes.push(hierarchyItem.index);
  127. if (expandedPathsHash && expandedPathsHash[pathHash] || dimension.expanded) {
  128. if (!hierarchyItem.children) {
  129. hierarchyItem.children = []
  130. }
  131. fillHierarchyItemIndexesCore(indexes, options, hierarchyItem.children, expandIndex + 1, pathHash)
  132. }
  133. }
  134. }
  135. function generateHierarchyItems(data, loadOptions, headers, headerName) {
  136. var result = [0];
  137. var expandIndex = loadOptions.headerName === headerName ? loadOptions.path.length : 0;
  138. var expandedPaths = "rows" === headerName ? loadOptions.rowExpandedPaths : loadOptions.columnExpandedPaths;
  139. var options = {
  140. data: data,
  141. childrenHash: headers[headerName + "Hash"],
  142. dimensions: loadOptions[headerName],
  143. expandedPathsHash: loadOptions.headerName !== headerName && expandedPaths && expandedPaths.hash
  144. };
  145. fillHierarchyItemIndexesCore(result, options, headers[headerName], expandIndex);
  146. return result
  147. }
  148. function generateAggregationCells(data, cells, headers, options) {
  149. var cellSet = [];
  150. var x;
  151. var y;
  152. var rowIndexes = generateHierarchyItems(data, options, headers, "rows");
  153. var columnIndexes = generateHierarchyItems(data, options, headers, "columns");
  154. for (y = 0; y < rowIndexes.length; y++) {
  155. var rowIndex = rowIndexes[y];
  156. cells[rowIndex] = cells[rowIndex] || [];
  157. for (x = 0; x < columnIndexes.length; x++) {
  158. var columnIndex = columnIndexes[x];
  159. cellSet.push(cells[rowIndex][columnIndex] = cells[rowIndex][columnIndex] || [])
  160. }
  161. }
  162. return cellSet
  163. }
  164. function fillHashExpandedPath(expandedPaths) {
  165. if (expandedPaths) {
  166. var hash = expandedPaths.hash = {};
  167. expandedPaths.forEach(function(path) {
  168. var pathValue = path.map(function(value) {
  169. return value + ""
  170. }).join(PATH_DELIMETER);
  171. hash[pathValue] = true
  172. })
  173. }
  174. }
  175. function prepareLoadOption(options) {
  176. options.rows = options.rows || [];
  177. options.columns = options.columns || [];
  178. options.filters = options.filters || [];
  179. fillHashExpandedPath(options.columnExpandedPaths);
  180. fillHashExpandedPath(options.rowExpandedPaths);
  181. prepareFields(options.columns);
  182. prepareFields(options.rows);
  183. prepareFields(options.values);
  184. prepareFields(options.filters)
  185. }
  186. function getAggregator(field) {
  187. if ("custom" === field.summaryType) {
  188. field.calculateCustomSummary = field.calculateCustomSummary || _common.noop;
  189. return {
  190. seed: function() {
  191. var options = {
  192. summaryProcess: "start",
  193. totalValue: void 0
  194. };
  195. field.calculateCustomSummary(options);
  196. return options
  197. },
  198. step: function(options, value) {
  199. options.summaryProcess = "calculate";
  200. options.value = value;
  201. field.calculateCustomSummary(options);
  202. return options
  203. },
  204. finalize: function(options) {
  205. options.summaryProcess = "finalize";
  206. delete options.value;
  207. field.calculateCustomSummary(options);
  208. return options.totalValue
  209. }
  210. }
  211. }
  212. return _utils.aggregators[field.summaryType] || _utils.aggregators.count
  213. }
  214. function aggregationStep(measures, aggregationCells, data) {
  215. for (var aggregatorIndex = 0; aggregatorIndex < measures.length; aggregatorIndex++) {
  216. var cellField = measures[aggregatorIndex];
  217. var cellValue = cellField.selector(data);
  218. var aggregator = getAggregator(cellField);
  219. var isAggregatorSeedFunction = "function" === typeof aggregator.seed;
  220. for (var cellSetIndex = 0; cellSetIndex < aggregationCells.length; cellSetIndex++) {
  221. var cell = aggregationCells[cellSetIndex];
  222. if (cell.length <= aggregatorIndex) {
  223. cell[aggregatorIndex] = isAggregatorSeedFunction ? aggregator.seed() : aggregator.seed
  224. }
  225. if (void 0 === cell[aggregatorIndex]) {
  226. cell[aggregatorIndex] = cellValue
  227. } else {
  228. if ((0, _type.isDefined)(cellValue)) {
  229. cell[aggregatorIndex] = aggregator.step(cell[aggregatorIndex], cellValue)
  230. }
  231. }
  232. }
  233. }
  234. }
  235. function aggregationFinalize(measures, cells) {
  236. (0, _iterator.each)(measures, function(aggregatorIndex, cellField) {
  237. var aggregator = getAggregator(cellField);
  238. if (aggregator.finalize) {
  239. (0, _iterator.each)(cells, function(_, row) {
  240. (0, _iterator.each)(row, function(_, cell) {
  241. if (cell && void 0 !== cell[aggregatorIndex]) {
  242. cell[aggregatorIndex] = aggregator.finalize(cell[aggregatorIndex])
  243. }
  244. })
  245. })
  246. }
  247. })
  248. }
  249. function areValuesEqual(filterValue, fieldValue) {
  250. var valueOfFilter = filterValue && filterValue.valueOf();
  251. var valueOfField = fieldValue && fieldValue.valueOf();
  252. if (Array.isArray(filterValue)) {
  253. fieldValue = fieldValue || [];
  254. for (var i = 0; i < filterValue.length; i++) {
  255. valueOfFilter = filterValue[i] && filterValue[i].valueOf();
  256. valueOfField = fieldValue[i] && fieldValue[i].valueOf();
  257. if (valueOfFilter !== valueOfField) {
  258. return false
  259. }
  260. }
  261. return true
  262. } else {
  263. return valueOfFilter === valueOfField
  264. }
  265. }
  266. function getGroupValue(levels, data) {
  267. var value = [];
  268. (0, _iterator.each)(levels, function(_, field) {
  269. value.push(field.selector(data))
  270. });
  271. return value
  272. }
  273. function createDimensionFilters(dimension) {
  274. var filters = [];
  275. (0, _iterator.each)(dimension, function(_, field) {
  276. var filterValues = field.filterValues || [];
  277. var groupName = field.groupName;
  278. if (groupName && (0, _type.isNumeric)(field.groupIndex)) {
  279. return
  280. }
  281. var filter = function(dataItem) {
  282. var value = field.levels ? getGroupValue(field.levels, dataItem) : field.selector(dataItem);
  283. var result = false;
  284. for (var i = 0; i < filterValues.length; i++) {
  285. if (areValuesEqual(filterValues[i], value)) {
  286. result = true;
  287. break
  288. }
  289. }
  290. return "exclude" === field.filterType ? !result : result
  291. };
  292. filterValues.length && filters.push(filter)
  293. });
  294. return filters
  295. }
  296. function createFilter(options) {
  297. var filters = createDimensionFilters(options.rows).concat(createDimensionFilters(options.columns)).concat(createDimensionFilters(options.filters));
  298. var expandedDimensions = options[options.headerName];
  299. var path = options.path;
  300. if (expandedDimensions) {
  301. filters.push(function(dataItem) {
  302. for (var i = 0; i < path.length; i++) {
  303. var expandValue = expandedDimensions[i].selector(dataItem);
  304. if ((0, _data.toComparable)(expandValue, true) !== (0, _data.toComparable)(path[i], true)) {
  305. return false
  306. }
  307. }
  308. return true
  309. })
  310. }
  311. return function(dataItem) {
  312. for (var i = 0; i < filters.length; i++) {
  313. if (!filters[i](dataItem)) {
  314. return false
  315. }
  316. }
  317. return true
  318. }
  319. }
  320. function loadCore(items, options, notifyProgress) {
  321. var headers = {
  322. columns: [],
  323. rows: [],
  324. columnsHash: {
  325. length: 1
  326. },
  327. rowsHash: {
  328. length: 1
  329. }
  330. };
  331. var values = [];
  332. var d = new _deferred.Deferred;
  333. var i = 0;
  334. var filter = createFilter(options);
  335. function processData() {
  336. var t = new Date;
  337. var startIndex = i;
  338. for (; i < items.length; i++) {
  339. if (i > startIndex && i % 1e4 === 0) {
  340. if (new Date - t >= 300) {
  341. notifyProgress(i / items.length);
  342. setTimeout(processData, 0);
  343. return
  344. }
  345. }
  346. var data = items[i];
  347. if (filter(data)) {
  348. var aggregationCells = generateAggregationCells(data, values, headers, options);
  349. aggregationStep(options.values, aggregationCells, data)
  350. }
  351. }
  352. aggregationFinalize(options.values, values);
  353. notifyProgress(1);
  354. d.resolve({
  355. rows: headers.rows,
  356. columns: headers.columns,
  357. values: values,
  358. grandTotalRowIndex: 0,
  359. grandTotalColumnIndex: 0
  360. })
  361. }
  362. processData();
  363. return d
  364. }
  365. function filterDataSource(dataSource, fieldSelectors) {
  366. var filter = dataSource.filter();
  367. if (dataSource.store() instanceof _custom_store2.default && filter) {
  368. filter = processFilter(filter, fieldSelectors);
  369. return (0, _query2.default)(dataSource.items()).filter(filter).toArray()
  370. }
  371. return dataSource.items()
  372. }
  373. function loadDataSource(dataSource, fieldSelectors, reload) {
  374. var d = new _deferred.Deferred;
  375. var customizeStoreLoadOptionsHandler = function(options) {
  376. if (dataSource.store() instanceof _array_store2.default) {
  377. options.storeLoadOptions.filter = processFilter(options.storeLoadOptions.filter, fieldSelectors)
  378. }
  379. };
  380. dataSource.on("customizeStoreLoadOptions", customizeStoreLoadOptionsHandler);
  381. if (!dataSource.isLoaded() || reload) {
  382. var loadDeferred = reload ? dataSource.load() : dataSource.reload();
  383. (0, _deferred.when)(loadDeferred).done(function() {
  384. loadDataSource(dataSource, fieldSelectors).done(function() {
  385. d.resolve(filterDataSource(dataSource, fieldSelectors))
  386. }).fail(d.reject)
  387. }).fail(d.reject)
  388. } else {
  389. d.resolve(filterDataSource(dataSource, fieldSelectors))
  390. }
  391. return d.always(function() {
  392. dataSource.off("customizeStoreLoadOptions", customizeStoreLoadOptionsHandler)
  393. })
  394. }
  395. function fillSelectorsByFields(selectors, fields) {
  396. fields.forEach(function(field) {
  397. if (field.dataField && "date" === field.dataType) {
  398. var valueSelector = getDateValue(getDataSelector(field.dataField));
  399. selectors[field.dataField] = function(data) {
  400. return valueSelector(data)
  401. }
  402. }
  403. })
  404. }
  405. function getFieldSelectors(options) {
  406. var selectors = {};
  407. if (Array.isArray(options)) {
  408. fillSelectorsByFields(selectors, options)
  409. } else {
  410. if (options) {
  411. ["rows", "columns", "filters"].forEach(function(area) {
  412. options[area] && fillSelectorsByFields(selectors, options[area])
  413. })
  414. }
  415. }
  416. return selectors
  417. }
  418. function processFilter(filter, fieldSelectors) {
  419. if (!Array.isArray(filter)) {
  420. return filter
  421. }
  422. filter = filter.slice(0);
  423. if ((0, _type.isString)(filter[0]) && (filter[1] instanceof Date || filter[2] instanceof Date)) {
  424. filter[0] = fieldSelectors[filter[0]]
  425. }
  426. for (var i = 0; i < filter.length; i++) {
  427. filter[i] = processFilter(filter[i], fieldSelectors)
  428. }
  429. return filter
  430. }
  431. return {
  432. ctor: function(options) {
  433. this._progressChanged = options.onProgressChanged || _common.noop;
  434. this._dataSource = new _data_source.DataSource(options);
  435. this._dataSource.paginate(false)
  436. },
  437. getFields: function(fields) {
  438. var that = this;
  439. var dataSource = that._dataSource;
  440. var d = new _deferred.Deferred;
  441. loadDataSource(dataSource, getFieldSelectors(fields)).done(function(data) {
  442. d.resolve((0, _uiPivot_grid.discoverObjectFields)(data, fields))
  443. }).fail(d.reject);
  444. return d
  445. },
  446. key: function() {
  447. return this._dataSource.key()
  448. },
  449. load: function(options) {
  450. var that = this;
  451. var dataSource = that._dataSource;
  452. var d = new _deferred.Deferred;
  453. prepareLoadOption(options);
  454. loadDataSource(dataSource, getFieldSelectors(options), options.reload).done(function(data) {
  455. (0, _deferred.when)(loadCore(data, options, that._progressChanged)).done(d.resolve)
  456. }).fail(d.reject);
  457. return d
  458. },
  459. filter: function() {
  460. var dataSource = this._dataSource;
  461. return dataSource.filter.apply(dataSource, arguments)
  462. },
  463. supportPaging: function() {
  464. return false
  465. },
  466. getDrillDownItems: function(loadOptions, params) {
  467. loadOptions = loadOptions || {};
  468. params = params || {};
  469. prepareLoadOption(loadOptions);
  470. var drillDownItems = [];
  471. var items = this._dataSource.items();
  472. var item;
  473. var maxRowCount = params.maxRowCount;
  474. var customColumns = params.customColumns;
  475. var filter = createFilter(loadOptions);
  476. var pathFilter = createFilter({
  477. rows: (0, _uiPivot_grid.getFiltersByPath)(loadOptions.rows, params.rowPath),
  478. columns: (0, _uiPivot_grid.getFiltersByPath)(loadOptions.columns, params.columnPath),
  479. filters: []
  480. });
  481. for (var i = 0; i < items.length; i++) {
  482. if (pathFilter(items[i]) && filter(items[i])) {
  483. if (customColumns) {
  484. item = {};
  485. for (var j = 0; j < customColumns.length; j++) {
  486. item[customColumns[j]] = items[i][customColumns[j]]
  487. }
  488. } else {
  489. item = items[i]
  490. }
  491. drillDownItems.push(item)
  492. }
  493. if (maxRowCount > 0 && drillDownItems.length === maxRowCount) {
  494. break
  495. }
  496. }
  497. return drillDownItems
  498. }
  499. }
  500. }()).include(_uiPivot_grid.storeDrillDownMixin);