'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Licensed Materials - Property of IBM * IBM Cognos Products: Dashboard * (C) Copyright IBM Corp. 2016, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['../../../widgets/livewidget/nls/StringResources', '../../../util/DashboardFormatter', '../../../util/ArrayUtils', './GridEdgeIterator', './Summary', '../../../extensions/client-summaries/content-features/SummaryTypes', '../../../widgets/livewidget/query/QueryResultDataUtils'], function (StringResources, Formatter, ArrayUtils, GridEdgeIterator, Summary, SummaryTypes, QueryResultDataUtils) { 'use strict'; var SUMMARY_ID = StringResources.get('summaryCaption'); var NOT_AVAILABLE = StringResources.get('value_is_not_available'); var UNDEFINED = 'undefined'; var NONE = 'none'; var OBJECT = 'object'; var OVERALL = 'overall'; var getUseValue = function getUseValue(oValue) { return oValue && _typeof(oValue.value) !== UNDEFINED ? oValue.value : oValue; }; var getKeys = function getKeys(aData, bData) { var aKeys = []; if (Array.isArray(aData)) { for (var i = 0; i < aData.length; i++) { aKeys.push(getUseValue(aData[i])); } } if ((typeof bData === 'undefined' ? 'undefined' : _typeof(bData)) !== UNDEFINED) { aKeys.push(getUseValue(bData)); } return aKeys.toString(); }; /** * !!! PERFORMANCE WARNING !!! * This class manipulates potentially very large amounts of data on the client. Any line of code may be * executed millions of times to render a single visualization, so should be as optimized as possible. */ var GridDataProcessor = function () { function GridDataProcessor(options) { var _this = this; _classCallCheck(this, GridDataProcessor); this._queryResult = options.queryResult; this._numberOfColumns = options.numberOfColumns || 0; this._lastGroupedColumnIndex = options.lastGroupedColumnIndex || 0; this._ungroupedColumnsInfo = []; this._rankDataItems = options.rankDataItems || []; this._columnSlot = options.columnSlot; this._columnDataItems = options.columnDataItems || []; this._getRankFormat = options.getRankFormat; this._getRealColumnIndex = options.getRealColumnIndex; this._valuesMap = {}; this._exceedsColumnThreshold = options.exceedsColumnThreshold || false; this._numberOfAttributeColumns = this._numberOfColumns - (options.factColumnIndices ? options.factColumnIndices.length : 0); this._doSummary = options.doSummary; this.summaryAPI = options.summaryFeature; this.summaryNotSupported = this.summaryAPI && this.summaryAPI.isNotSupported(); this._onCellDataChange = options.onCellDataChange; this._summaryValuePromises = []; this._factColumnsMap = {}; Array.isArray(options.factColumnIndices) && options.factColumnIndices.forEach(function (index) { return _this._factColumnsMap[index] = true; }); } /** * onCellDataChange callback wrapper for formatted values * @param {number} row row index * @param {number} col column index * @param {string} value cell value * @param {object} formatSpec format specification for formatting the value */ GridDataProcessor.prototype.onCellDataChange = function onCellDataChange(row, col, value, formatSpec) { // CADBLOC-1398: summary value should show N/A when it is not available var rawValue = value && value.u ? value.u : value || NOT_AVAILABLE; this._onCellDataChange(row, col, Formatter.format(rawValue, formatSpec || null), rawValue); }; GridDataProcessor.prototype._setUngroupedColumnsInfo = function _setUngroupedColumnsInfo() { for (var columnIndex = this._lastGroupedColumnIndex; columnIndex < this._numberOfColumns; columnIndex++) { var dataItem = this._columnDataItems[columnIndex]; var isRankDataItem = dataItem.isRank && dataItem.isRank(); var info = { 'dataItemUniqueId': dataItem.getId(), 'formatSpec': this._getSlotFormat(columnIndex), 'id': dataItem.getId(), 'index': columnIndex, 'aggregationType': dataItem.getAggregation(), 'addSummary': !isRankDataItem && this._columnSlot.getDataItemList()[this._getRealColumnIndex(columnIndex)].getAggregation() !== NONE }; this._ungroupedColumnsInfo.push(info); } }; GridDataProcessor.prototype._getSlotFormat = function _getSlotFormat(index) { var formatSpec = void 0; var dataItemList = this._columnSlot.getDataItemList(); if (this._rankDataItems.length) { if (this._columnDataItems[index].isRank) { formatSpec = this._getRankFormat(); } else { formatSpec = dataItemList[index - this._rankDataItems.length].getFormat(); } } else { formatSpec = dataItemList[index].getFormat(); } return formatSpec; }; GridDataProcessor.prototype._generateNewDataTableWithOrder = function _generateNewDataTableWithOrder() { if (this._doSummary) { return this._preProcessedData.length ? this._preProcessedData : this._rawData; } for (var index = 0; index < this._rawData.length; index++) { var queryDataRow = this._rawData[index]; var matchingIndex = -1; for (var i = 0; i < this._preProcessedData.length; i++) { var preProcessedDataRow = this._preProcessedData[i]; if (!preProcessedDataRow) { continue; } if (this._rankDataItems.length > 0) { // in this scenario, only comparing edge rank value is sufficient since column index does not change and rank info is unique var preProcessedDataRowEdgeValue = preProcessedDataRow[0] && preProcessedDataRow[0].value; if (!preProcessedDataRowEdgeValue) { continue; } var queryDataRowEdgetRank = queryDataRow[0].value; if (!queryDataRowEdgetRank) { continue; } var preProcessedDataRowEdgeRank = preProcessedDataRowEdgeValue.deco && preProcessedDataRowEdgeValue.deco.rank; if (!preProcessedDataRowEdgeRank) { continue; } if (preProcessedDataRowEdgeRank === queryDataRowEdgetRank) { matchingIndex = i; break; } } else { // in this scenario, we need to compare the dataPoint value var preProcessedDataRowValue = preProcessedDataRow.map(function (item) { return item.value && _typeof(item.value.value) !== UNDEFINED ? item.value.value : item.value; }); var queryDataRowValue = []; for (var j = 0; j < queryDataRow.length; j++) { var row = queryDataRow[j]; if (Array.isArray(row)) { for (var k = 0; k < row.length; k++) { if (_typeof(row[k].value) !== UNDEFINED) { queryDataRowValue.push(row[k].value); } } } else if (_typeof(row.value) !== UNDEFINED) { queryDataRowValue.push(row.value); } } if (ArrayUtils.isArrayInArray(queryDataRowValue, preProcessedDataRowValue)) { matchingIndex = i; break; } } } if (matchingIndex !== -1) { this._rawData[index] = this._preProcessedData[matchingIndex]; this._preProcessedData[matchingIndex] = null; } } return this._rawData; }; GridDataProcessor.prototype.getData = function getData() { this._rawData = QueryResultDataUtils.getResolvedDataRows(this._queryResult); if (this._exceedsColumnThreshold) { // if ranking is applied or summary is disabled, we should respect the sort order of the query result return Promise.resolve(this._rawData); } else { // Promise-ifying this as a chain to allow time between the expensive steps for // the rest of the UI to react. Long-running return Promise.resolve().then(this._setUngroupedColumnsInfo.bind(this)).then(this._generateIntermediateObjects.bind(this)).then(this._generateNewDataTableWithSummaries.bind(this)).then(this._generateNewDataTableWithOrder.bind(this)); } }; /* * Generates grouped columns traversal object and a values map containing summaries. */ GridDataProcessor.prototype._generateIntermediateObjects = function _generateIntermediateObjects() { //an intermediate object which the iterator will traverse to get grouped column and summaries info //used to generate the keys for indexing into the values map. var dataRowCount = this._queryResult.getRowCount(); var container = {}; var attributeRowValues = void 0; for (var rowIdx = 0; rowIdx < dataRowCount; rowIdx++) { attributeRowValues = this._getAttributeValuesInTheRow(rowIdx); this._addRowValuesToGroupedItemsContainer(container, attributeRowValues, rowIdx); this._generateIntermediateObjectsForUngroupedColumns(attributeRowValues, rowIdx); } return this._addSortKeysToContainer(container); }; GridDataProcessor.prototype._generateIntermediateObjectsForUngroupedColumns = function _generateIntermediateObjectsForUngroupedColumns(attributeRowValues, rowIdx) { var ungroupedColumnInfo = void 0, value = void 0, rowValue = void 0, cellIdx = void 0, key = void 0, useValue = void 0, end = void 0, summaryKey = void 0, currentSummaryValue = void 0; for (var idx = 0, j = this._lastGroupedColumnIndex; j < this._numberOfColumns; j++, idx++) { ungroupedColumnInfo = this._ungroupedColumnsInfo[idx]; value = this._getCellValue(rowIdx, j); cellIdx = rowIdx + ':' + j; if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== UNDEFINED) { useValue = getUseValue(value); if ((typeof useValue === 'undefined' ? 'undefined' : _typeof(useValue)) !== UNDEFINED && useValue !== null) { rowValue = attributeRowValues.concat(ungroupedColumnInfo.dataItemUniqueId); key = getKeys(rowValue); this._valuesMap[key] = { value: value, cellIdx: cellIdx }; if (ungroupedColumnInfo.addSummary && ungroupedColumnInfo.aggregationType) { var keyUIds = { summaryKeys: [], oCategoryAndTupleUIds: {}, isLocalSummary: this._isLocalSummary(ungroupedColumnInfo.aggregationType) }; // groups not including the last attribute and measure end = rowValue.length - 2; for (; end >= 0; --end) { rowValue[end] = SUMMARY_ID; summaryKey = getKeys(rowValue); keyUIds.summaryKeys.push(summaryKey); var categoryAndTupleUId = { categoryUIds: [], tupleUIds: [] }; if (!(keyUIds.isLocalSummary || this.summaryNotSupported || keyUIds.oCategoryAndTupleUIds[summaryKey])) { for (var i = 0; i < this._columnDataItems.length; i++) { if (_typeof(rowValue[i]) === OBJECT) { categoryAndTupleUId.categoryUIds.push(this._columnDataItems[i].getId()); categoryAndTupleUId.tupleUIds.push(rowValue[i].value); } } } keyUIds.oCategoryAndTupleUIds[summaryKey] = categoryAndTupleUId; currentSummaryValue = this._valuesMap[summaryKey]; if (!currentSummaryValue && ungroupedColumnInfo) { currentSummaryValue = new Summary(ungroupedColumnInfo, keyUIds.isLocalSummary); if (!this.summaryNotSupported && !keyUIds.isLocalSummary) { // Add call back context to update values once resolved currentSummaryValue.addCallBackContext({ categoryUIds: keyUIds.oCategoryAndTupleUIds[summaryKey].categoryUIds, tupleUIds: keyUIds.oCategoryAndTupleUIds[summaryKey].tupleUIds, cbOnCellDataChange: this.onCellDataChange.bind(this), cbGetSummary: this.summaryAPI ? this.summaryAPI.getSummary.bind(this.summaryAPI) : undefined, cbAddSummaryValuePromise: this.cacheSummaryValuePromise.bind(this) }); } } if (currentSummaryValue) { currentSummaryValue.addValue(useValue); } this._valuesMap[summaryKey] = currentSummaryValue; } } } } } }; /** * Retrieve a cell value for grid * * @param {number} rowIdx - the row index value * @param {number} columnIdx - the column index value * * @return {object} the cell value object */ GridDataProcessor.prototype._getCellValue = function _getCellValue(rowIdx, columnIdx) { var value = this._queryResult.getValue(rowIdx, columnIdx); return value instanceof Array && !!value.length ? value[0] : value; }; GridDataProcessor.prototype._getAttributeValuesInTheRow = function _getAttributeValuesInTheRow(rowIdx) { var attributeRowValues = []; for (var colIdx = 0; colIdx < this._numberOfColumns; colIdx++) { if (!this._factColumnsMap[colIdx]) { attributeRowValues.push(this._getCellValue(rowIdx, colIdx)); } } return attributeRowValues; }; /** * Returns a new object with Summary as the last item to be used for iterating */ GridDataProcessor.prototype._addSortKeysToContainer = function _addSortKeysToContainer(edge) { var hasSummary = false; var newEdgeObject = { edge: edge, sortedKeys: [] }; for (var key in edge) { if (edge.hasOwnProperty(key)) { if (key === SUMMARY_ID) { hasSummary = true; } else { newEdgeObject.sortedKeys.push(key); var nestedEdges = edge[key].nestedEdges; if (nestedEdges) { edge[key].nestedEdges = this._addSortKeysToContainer(nestedEdges); } } } } if (hasSummary) { newEdgeObject.sortedKeys.push(SUMMARY_ID); var _nestedEdges = edge[SUMMARY_ID].nestedEdges; if (_nestedEdges) { edge[SUMMARY_ID].nestedEdges = this._addSortKeysToContainer(_nestedEdges); } } return newEdgeObject; }; GridDataProcessor.prototype._addRowValuesToGroupedItemsContainer = function _addRowValuesToGroupedItemsContainer(container, attributeRowValues, rowIndex, columnIndex, ancestor) { var attributeRowValueIndex = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; columnIndex = columnIndex || 0; if (attributeRowValues && attributeRowValues.length > 0) { var rowValue = attributeRowValues[attributeRowValueIndex].value; if (!container[rowValue]) { container[rowValue] = { value: attributeRowValues[attributeRowValueIndex], level: columnIndex, cellIdx: rowIndex + ':' + columnIndex }; if (this._doSummary) { this._addSummaryToGroupedItemsContainer(container, columnIndex, ancestor); } } var nextAttributeRowValueIndex = attributeRowValueIndex + 1; if (nextAttributeRowValueIndex < attributeRowValues.length) { if (!container[rowValue].nestedEdges) { container[rowValue].nestedEdges = {}; } this._addRowValuesToGroupedItemsContainer(container[rowValue].nestedEdges, attributeRowValues, rowIndex, columnIndex + 1, rowValue, nextAttributeRowValueIndex); } } }; GridDataProcessor.prototype._addSummaryToGroupedItemsContainer = function _addSummaryToGroupedItemsContainer(container, columnIndex, ancestor, bIsOverallSummary) { var isOverallSummary = bIsOverallSummary || columnIndex === 0; if (columnIndex < this._numberOfAttributeColumns) { var summaryNode = { isSummary: true, level: columnIndex, isOverallSummary: isOverallSummary, summaryOf: isOverallSummary ? OVERALL : ancestor }; container[SUMMARY_ID] = summaryNode; if (columnIndex < this._numberOfAttributeColumns - 1) { //special handling for overall summary in order for the crosstab to render the summary column correctly //need to add as many summary as nested levels summaryNode.nestedEdges = {}; this._addSummaryToGroupedItemsContainer(summaryNode.nestedEdges, columnIndex + 1, ancestor, isOverallSummary); } } }; /** * caching the summary value promise * * @param {object} summary value promise; when resolved the summary value is available */ GridDataProcessor.prototype.cacheSummaryValuePromise = function cacheSummaryValuePromise(promise) { this._summaryValuePromises.push(promise); }; /** * Returns a promise indicating whether all summaries get in the grid */ GridDataProcessor.prototype.whenAllSummaryValuesAreReady = function whenAllSummaryValuesAreReady() { return Promise.all(this._summaryValuePromises); }; GridDataProcessor.prototype._getSummaryKeys = function _getSummaryKeys(attributeRowValues) { var summaryKeys = {}; //rowStart/rowEnd indicates starting/ending position in the originalDimension array that contains row info var rowEnd = this._numberOfAttributeColumns - 1; for (var rowStart = 0; rowEnd >= rowStart; --rowEnd) { attributeRowValues[rowEnd] = SUMMARY_ID; summaryKeys[getKeys(attributeRowValues)] = true; } return Object.keys(summaryKeys); }; GridDataProcessor.prototype._generateNewDataTableWithSummaries = function _generateNewDataTableWithSummaries(groupedColumnsTraversalObject) { var dataWithSummary = []; var nextGroupedItem = void 0; var dataTableRow = void 0; var rowIndex = 0; var groupedColumnsRowIterator = new GridEdgeIterator(groupedColumnsTraversalObject, undefined); while (nextGroupedItem = groupedColumnsRowIterator.next()) { dataTableRow = []; this._addGroupedItemsToRow(dataTableRow, nextGroupedItem); this._addValuesToRow(dataTableRow, nextGroupedItem, ++rowIndex); dataWithSummary.push(dataTableRow); } this._preProcessedData = dataWithSummary; }; GridDataProcessor.prototype._addGroupedItemsToRow = function _addGroupedItemsToRow(dataTableRow, firstGroupedItem) { var nextColumn = firstGroupedItem; var columnIndex = 0; while (nextColumn && columnIndex < this._lastGroupedColumnIndex) { dataTableRow.push(nextColumn); nextColumn = nextColumn.subCategory; columnIndex++; } }; /* * This function adds fact value or attribute value which is not grouped. */ GridDataProcessor.prototype._addValuesToRow = function _addValuesToRow(dataTableRow, firstGroupedItem, rowIndex) { for (var columnIndex = 0; columnIndex < this._ungroupedColumnsInfo.length; columnIndex++) { var nextColumn = this._ungroupedColumnsInfo[columnIndex]; var key = getKeys(firstGroupedItem.descendant_or_self, nextColumn.dataItemUniqueId); var valueObj = this._valuesMap[key] || null; var data = null; var rawValue = null; if (valueObj) { if (valueObj.getSummarizedValue) { if (!valueObj._isLocalSummary) { data = valueObj.getSummarizedValue(rowIndex, nextColumn.index); } else if (valueObj.getValue() !== null) { rawValue = valueObj.getValue(); data = Formatter.formatNull(rawValue, valueObj._formatSpec || null); } else { data = valueObj.value; } } else { data = valueObj.value; } } var result = data; if (!result) { //for summary of attribute column which is ungrouped if (firstGroupedItem.isSummary && !nextColumn.aggregationType) { result = ' '; } } dataTableRow.push({ isSummary: firstGroupedItem.isSummary, value: result, rawValue: rawValue, key: key, cellIdx: valueObj ? valueObj.cellIdx : null, isOverallSummary: firstGroupedItem.isOverallSummary }); } }; GridDataProcessor.prototype._isLocalSummary = function _isLocalSummary(aggregationType) { return SummaryTypes.indexOf(aggregationType) === -1; }; return GridDataProcessor; }(); return GridDataProcessor; }); //# sourceMappingURL=GridDataProcessor.js.map