From 498c10aab4076409128734c215f808995d6cbdf2 Mon Sep 17 00:00:00 2001 From: "Alex.V" Date: Thu, 25 Jun 2020 21:53:58 +0200 Subject: [PATCH] fix(cubejs-client-react): order heuristic (#758) --- .../dist/cubejs-client-react.esm.js | 29 ++- .../dist/cubejs-client-react.js | 29 ++- .../dist/cubejs-client-react.umd.js | 225 +++++++++++------- .../cubejs-client-react/src/QueryBuilder.jsx | 20 +- 4 files changed, 172 insertions(+), 131 deletions(-) diff --git a/packages/cubejs-client-react/dist/cubejs-client-react.esm.js b/packages/cubejs-client-react/dist/cubejs-client-react.esm.js index 8913efe218e66..50fab670b88f4 100644 --- a/packages/cubejs-client-react/dist/cubejs-client-react.esm.js +++ b/packages/cubejs-client-react/dist/cubejs-client-react.esm.js @@ -431,7 +431,6 @@ function (_React$Component) { orderMembers: [], pivotConfig: null }, props.vizState); - _this.shouldApplyHeuristicOrder = false; _this.mutexObj = {}; return _this; } @@ -460,7 +459,7 @@ function (_React$Component) { meta: meta, query: query }), - pivotConfig: QueryRenderer.isQueryPresent(query) ? ResultSet.getNormalizedPivotConfig(query) : pivotConfig + pivotConfig: ResultSet.getNormalizedPivotConfig(query || {}, pivotConfig) }); case 5: @@ -573,8 +572,8 @@ function (_React$Component) { return m.type === 'time'; }), availableSegments: meta && meta.membersForQuery(query, 'segments') || [], - updateQuery: function updateQuery(query) { - return _this2.updateQuery(query); + updateQuery: function updateQuery(queryUpdate) { + return _this2.updateQuery(queryUpdate); }, updateMeasures: updateMethods('measures'), updateDimensions: updateMethods('dimensions'), @@ -675,23 +674,22 @@ function (_React$Component) { finalState = this.applyStateChangeHeuristics(state); _ref3 = finalState.query || {}, _ = _ref3.order, query = _objectWithoutProperties(_ref3, ["order"]); - if (!(this.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { - _context2.next = 11; + if (!(finalState.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { + _context2.next = 10; break; } - this.shouldApplyHeuristicOrder = false; - _context2.next = 8; + _context2.next = 7; return this.cubejsApi().sql(query, { mutexObj: this.mutexObj }); - case 8: + case 7: _ref4 = _context2.sent; sqlQuery = _ref4.sqlQuery; finalState.query.order = sqlQuery.sql.order; - case 11: + case 10: activePivotConfig = finalState.pivotConfig !== undefined ? finalState.pivotConfig : statePivotConfig; updatedOrderMembers = indexBy(prop('id'), QueryBuilder.getOrderMembers(_objectSpread2({}, this.state, {}, finalState))); currentOrderMemberIds = (finalState.orderMembers || []).map(function (_ref5) { @@ -736,7 +734,7 @@ function (_React$Component) { setVizState(toSet); } - case 23: + case 22: case "end": return _context2.stop(); } @@ -788,9 +786,9 @@ function (_React$Component) { granularity: defaultGranularity }] : [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: defaultTimeDimension ? 'line' : 'number' }); @@ -804,9 +802,9 @@ function (_React$Component) { }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: 'table' }); @@ -820,9 +818,9 @@ function (_React$Component) { }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number' }); @@ -833,9 +831,9 @@ function (_React$Component) { timeDimensions: [], filters: [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, sessionGranularity: null }); @@ -867,6 +865,7 @@ function (_React$Component) { return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: _objectSpread2({}, query, { timeDimensions: [_objectSpread2({}, _td, { granularity: undefined diff --git a/packages/cubejs-client-react/dist/cubejs-client-react.js b/packages/cubejs-client-react/dist/cubejs-client-react.js index dc0a680cb729b..a6eb618469507 100644 --- a/packages/cubejs-client-react/dist/cubejs-client-react.js +++ b/packages/cubejs-client-react/dist/cubejs-client-react.js @@ -438,7 +438,6 @@ function (_React$Component) { orderMembers: [], pivotConfig: null }, props.vizState); - _this.shouldApplyHeuristicOrder = false; _this.mutexObj = {}; return _this; } @@ -467,7 +466,7 @@ function (_React$Component) { meta: meta, query: query }), - pivotConfig: QueryRenderer.isQueryPresent(query) ? core.ResultSet.getNormalizedPivotConfig(query) : pivotConfig + pivotConfig: core.ResultSet.getNormalizedPivotConfig(query || {}, pivotConfig) }); case 5: @@ -580,8 +579,8 @@ function (_React$Component) { return m.type === 'time'; }), availableSegments: meta && meta.membersForQuery(query, 'segments') || [], - updateQuery: function updateQuery(query) { - return _this2.updateQuery(query); + updateQuery: function updateQuery(queryUpdate) { + return _this2.updateQuery(queryUpdate); }, updateMeasures: updateMethods('measures'), updateDimensions: updateMethods('dimensions'), @@ -682,23 +681,22 @@ function (_React$Component) { finalState = this.applyStateChangeHeuristics(state); _ref3 = finalState.query || {}, _ = _ref3.order, query = _objectWithoutProperties(_ref3, ["order"]); - if (!(this.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { - _context2.next = 11; + if (!(finalState.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { + _context2.next = 10; break; } - this.shouldApplyHeuristicOrder = false; - _context2.next = 8; + _context2.next = 7; return this.cubejsApi().sql(query, { mutexObj: this.mutexObj }); - case 8: + case 7: _ref4 = _context2.sent; sqlQuery = _ref4.sqlQuery; finalState.query.order = sqlQuery.sql.order; - case 11: + case 10: activePivotConfig = finalState.pivotConfig !== undefined ? finalState.pivotConfig : statePivotConfig; updatedOrderMembers = ramda.indexBy(ramda.prop('id'), QueryBuilder.getOrderMembers(_objectSpread2({}, this.state, {}, finalState))); currentOrderMemberIds = (finalState.orderMembers || []).map(function (_ref5) { @@ -743,7 +741,7 @@ function (_React$Component) { setVizState(toSet); } - case 23: + case 22: case "end": return _context2.stop(); } @@ -795,9 +793,9 @@ function (_React$Component) { granularity: defaultGranularity }] : [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: defaultTimeDimension ? 'line' : 'number' }); @@ -811,9 +809,9 @@ function (_React$Component) { }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: 'table' }); @@ -827,9 +825,9 @@ function (_React$Component) { }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number' }); @@ -840,9 +838,9 @@ function (_React$Component) { timeDimensions: [], filters: [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, sessionGranularity: null }); @@ -874,6 +872,7 @@ function (_React$Component) { return _objectSpread2({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: _objectSpread2({}, query, { timeDimensions: [_objectSpread2({}, _td, { granularity: undefined diff --git a/packages/cubejs-client-react/dist/cubejs-client-react.umd.js b/packages/cubejs-client-react/dist/cubejs-client-react.umd.js index f85c6f9cead2b..58ae7fa1ca659 100644 --- a/packages/cubejs-client-react/dist/cubejs-client-react.umd.js +++ b/packages/cubejs-client-react/dist/cubejs-client-react.umd.js @@ -34980,6 +34980,61 @@ var fetch = _interopDefault(browserPonyfill); /** + * Configuration object that contains information about pivot axes and other options. + * + * Let's apply `pivotConfig` and see how it affects the axes + * ```js + * // Example query + * { + * measures: ['Orders.count'], + * dimensions: ['Users.country', 'Users.gender'] + * } + * ``` + * If we put the `Users.gender` dimension on **y** axis + * ```js + * resultSet.tablePivot({ + * x: ['Users.country'], + * y: ['Users.gender', 'measures'] + * }) + * ``` + * + * The resulting table will look the following way + * + * | Users Country | male, Orders.count | female, Orders.count | + * | ------------- | ------------------ | -------------------- | + * | Australia | 3 | 27 | + * | Germany | 10 | 12 | + * | US | 5 | 7 | + * + * Now let's put the `Users.country` dimension on **y** axis instead + * ```js + * resultSet.tablePivot({ + * x: ['Users.gender'], + * y: ['Users.country', 'measures'], + * }); + * ``` + * + * in this case the `Users.country` values will be laid out on **y** or **columns** axis + * + * | Users Gender | Australia, Orders.count | Germany, Orders.count | US, Orders.count | + * | ------------ | ----------------------- | --------------------- | ---------------- | + * | male | 3 | 10 | 5 | + * | female | 27 | 12 | 7 | + * + * It's also possible to put the `measures` on **x** axis. + * But in either case it should always be the last item of the array. + * ```js + * resultSet.tablePivot({ + * x: ['Users.gender', 'measures'], + * y: ['Users.country'], + * }); + * ``` + * + * | Users Gender | measures | Australia | Germany | US | + * | ------------ | ------------ | --------- | ------- | --- | + * | male | Orders.count | 3 | 10 | 5 | + * | female | Orders.count | 27 | 12 | 7 | + * * @memberof ResultSet * @typedef {Object} PivotConfig Configuration object that contains the information about pivot axes and other options * @property {Array} x Dimensions to put on **x** or **rows** axis. @@ -35321,8 +35376,10 @@ } /** * Base method for pivoting {@link ResultSet} data. - * Most of the times shouldn't be used directly and {@link ResultSet#chartPivot} or {@link ResultSet#tablePivot} - * should be used instead. + * Most of the times shouldn't be used directly and {@link ResultSet#chartPivot} + * or {@link ResultSet#tablePivot} should be used instead. + * + * You can find the examples of using the `pivotConfig` [here](#pivot-config) * ```js * // For query * { @@ -35470,8 +35527,10 @@ } /** * Returns normalized query result data in the following format. + * + * You can find the examples of using the `pivotConfig` [here](#pivot-config) * ```js - * // For query + * // For the query * { * measures: ['Stories.count'], * timeDimensions: [{ @@ -35529,7 +35588,9 @@ /** * Returns normalized query result data prepared for visualization in the table format. * - * For example + * You can find the examples of using the `pivotConfig` [here](#pivot-config) + * + * For example: * ```js * // For the query * { @@ -35549,67 +35610,6 @@ * //... * ] * ``` - * - * Now let's make use of `pivotConfig` and put the `Users.gender` dimension on **y** axis. - * ```js - * // For example the query is - * { - * measures: ['Orders.count'], - * dimensions: ['Users.country', 'Users.gender'] - * } - * - * resultSet.tablePivot({ - * x: ['Users.country'], - * y: ['Users.gender', 'measures'] - * }) - * - * // then `tablePivot` will return the rows in the following format - * [ - * { - * 'Users.country': 'Australia', - * 'female.Orders.count': 3 - * 'male.Orders.count': 27 - * }, - * // ... - * ] - * ``` - * - * The resulting table will look like this - * - * | Users Country | male | female | - * | ------------- | ---- | ------ | - * | Australia | 3 | 27 | - * | Germany | 10 | 12 | - * | US | 5 | 7 | - * - * If we put the `Users.country` dimension on **y** axis instead - * ```js - * resultSet.tablePivot({ - * x: ['Users.gender'], - * y: ['Users.country', 'measures'], - * }); - * ``` - * - * the table will look like - * - * | Users Gender | Australia | Germany | US | - * | ------------ | --------- | ------- | --- | - * | male | 3 | 10 | 5 | - * | female | 27 | 12 | 7 | - * - * It's also possible to put the `measures` on **x** axis - * ```js - * resultSet.tablePivot({ - * x: ['Users.gender', 'measures'], - * y: ['Users.country'], - * }); - * ``` - * - * | Users Gender | measures | Australia | Germany | US | - * | ------------ | ------------ | --------- | ------- | --- | - * | male | Orders.count | 3 | 10 | 5 | - * | female | Orders.count | 27 | 12 | 7 | - * * @param {PivotConfig} [pivotConfig] * @returns {Array} of pivoted rows */ @@ -35635,7 +35635,7 @@ /** * Returns array of column definitions for `tablePivot`. * - * For example + * For example: * ```js * // For the query * { @@ -35669,7 +35669,7 @@ * ] * ``` * - * In case we want to pivot the table + * In case we want to pivot the table axes * ```js * // Let's take this query as an example * { @@ -35759,7 +35759,8 @@ }; }; - this.pivot(normalizedPivotConfig)[0].yValuesArray.forEach(function (_ref31) { + var pivot = this.pivot(normalizedPivotConfig); + (pivot[0] && pivot[0].yValuesArray || []).forEach(function (_ref31) { var _ref32 = _slicedToArray$$1(_ref31, 1), yValues = _ref32[0]; @@ -35815,6 +35816,18 @@ }); }; + var measureColumns = []; + + if (!pivot.length && normalizedPivotConfig.y.find(function (key) { + return key === 'measures'; + })) { + measureColumns = (this.query().measures || []).map(function (key) { + return _objectSpread2({}, extractFields(key), { + dataIndex: key + }); + }); + } + return normalizedPivotConfig.x.map(function (key) { if (key === 'measures') { return { @@ -35829,7 +35842,44 @@ return _objectSpread2({}, extractFields(key), { dataIndex: key }); - }).concat(toColumns(schema)); + }).concat(toColumns(schema)).concat(measureColumns); + } + }, { + key: "tableColumns2", + value: function tableColumns2(pivotConfig) { + var _this5 = this; + + var normalizedPivotConfig = this.normalizePivotConfig(pivotConfig); + + var column = function column(field) { + var exractFields = function exractFields() { + var annotation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var title = annotation.title, + shortTitle = annotation.shortTitle, + format = annotation.format, + type = annotation.type, + meta = annotation.meta; + return { + title: title, + shortTitle: shortTitle, + format: format, + type: type, + meta: meta + }; + }; + + return field === 'measures' ? (_this5.query().measures || []).map(function (key) { + return _objectSpread2({ + key: key + }, exractFields(_this5.loadResponse.annotation.measures[key])); + }) : [_objectSpread2({ + key: field + }, exractFields(_this5.loadResponse.annotation.dimensions[field] || _this5.loadResponse.annotation.timeDimensions[field]))]; + }; + + return normalizedPivotConfig.x.map(column).concat(normalizedPivotConfig.y.map(column)).reduce(function (a, b) { + return a.concat(b); + }); } }, { key: "totalRow", @@ -35871,15 +35921,15 @@ }, { key: "seriesNames", value: function seriesNames(pivotConfig) { - var _this5 = this; + var _this6 = this; pivotConfig = this.normalizePivotConfig(pivotConfig); return ramda.pipe(ramda.map(this.axisValues(pivotConfig.y)), ramda.unnest, ramda.uniq)(this.timeDimensionBackwardCompatibleData()).map(function (axisValues) { return { - title: _this5.axisValuesString(pivotConfig.y.find(function (d) { + title: _this6.axisValuesString(pivotConfig.y.find(function (d) { return d === 'measures'; - }) ? ramda.dropLast(1, axisValues).concat(_this5.loadResponse.annotation.measures[ResultSet.measureFromAxis(axisValues)].title) : axisValues, ', '), - key: _this5.axisValuesString(axisValues), + }) ? ramda.dropLast(1, axisValues).concat(_this6.loadResponse.annotation.measures[ResultSet.measureFromAxis(axisValues)].title) : axisValues, ', '), + key: _this6.axisValuesString(axisValues), yValues: axisValues }; }); @@ -37018,7 +37068,6 @@ orderMembers: [], pivotConfig: null }, props$$1.vizState); - _this.shouldApplyHeuristicOrder = false; _this.mutexObj = {}; return _this; } @@ -37047,7 +37096,7 @@ meta: meta, query: query }), - pivotConfig: QueryRenderer.isQueryPresent(query) ? cubejsClientCore_2.getNormalizedPivotConfig(query) : pivotConfig + pivotConfig: cubejsClientCore_2.getNormalizedPivotConfig(query || {}, pivotConfig) }); case 5: @@ -37160,8 +37209,8 @@ return m.type === 'time'; }), availableSegments: meta && meta.membersForQuery(query, 'segments') || [], - updateQuery: function updateQuery(query) { - return _this2.updateQuery(query); + updateQuery: function updateQuery(queryUpdate) { + return _this2.updateQuery(queryUpdate); }, updateMeasures: updateMethods('measures'), updateDimensions: updateMethods('dimensions'), @@ -37262,23 +37311,22 @@ finalState = this.applyStateChangeHeuristics(state); _ref3 = finalState.query || {}, _ = _ref3.order, query = _objectWithoutProperties(_ref3, ["order"]); - if (!(this.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { - _context2.next = 11; + if (!(finalState.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query))) { + _context2.next = 10; break; } - this.shouldApplyHeuristicOrder = false; - _context2.next = 8; + _context2.next = 7; return this.cubejsApi().sql(query, { mutexObj: this.mutexObj }); - case 8: + case 7: _ref4 = _context2.sent; sqlQuery = _ref4.sqlQuery; finalState.query.order = sqlQuery.sql.order; - case 11: + case 10: activePivotConfig = finalState.pivotConfig !== undefined ? finalState.pivotConfig : statePivotConfig; updatedOrderMembers = indexBy(prop('id'), QueryBuilder.getOrderMembers(_objectSpread({}, this.state, {}, finalState))); currentOrderMemberIds = (finalState.orderMembers || []).map(function (_ref5) { @@ -37323,7 +37371,7 @@ setVizState(toSet); } - case 23: + case 22: case "end": return _context2.stop(); } @@ -37375,9 +37423,9 @@ granularity: defaultGranularity }] : [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: defaultTimeDimension ? 'line' : 'number' }); @@ -37391,9 +37439,9 @@ }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: 'table' }); @@ -37407,9 +37455,9 @@ }); }) }); - this.shouldApplyHeuristicOrder = true; return _objectSpread({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number' }); @@ -37420,9 +37468,9 @@ timeDimensions: [], filters: [] }); - this.shouldApplyHeuristicOrder = true; return _objectSpread({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, sessionGranularity: null }); @@ -37454,6 +37502,7 @@ return _objectSpread({}, newState, { pivotConfig: null, + shouldApplyHeuristicOrder: true, query: _objectSpread({}, query, { timeDimensions: [_objectSpread({}, _td, { granularity: undefined diff --git a/packages/cubejs-client-react/src/QueryBuilder.jsx b/packages/cubejs-client-react/src/QueryBuilder.jsx index f0a9fa0c457f0..24ad399193d52 100644 --- a/packages/cubejs-client-react/src/QueryBuilder.jsx +++ b/packages/cubejs-client-react/src/QueryBuilder.jsx @@ -91,7 +91,6 @@ export default class QueryBuilder extends React.Component { ...props.vizState }; - this.shouldApplyHeuristicOrder = false; this.mutexObj = {}; } @@ -102,7 +101,7 @@ export default class QueryBuilder extends React.Component { this.setState({ meta, orderMembers: QueryBuilder.getOrderMembers({ meta, query }), - pivotConfig: QueryRenderer.isQueryPresent(query) ? ResultSet.getNormalizedPivotConfig(query) : pivotConfig + pivotConfig: ResultSet.getNormalizedPivotConfig(query || {}, pivotConfig) }); } @@ -273,9 +272,7 @@ export default class QueryBuilder extends React.Component { let finalState = this.applyStateChangeHeuristics(state); const { order: _, ...query } = finalState.query || {}; - if (this.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query)) { - this.shouldApplyHeuristicOrder = false; - + if (finalState.shouldApplyHeuristicOrder && QueryRenderer.isQueryPresent(query)) { const { sqlQuery } = await this.cubejsApi().sql(query, { mutexObj: this.mutexObj }); @@ -373,11 +370,10 @@ export default class QueryBuilder extends React.Component { : [] }; - this.shouldApplyHeuristicOrder = true; - return { ...newState, pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: defaultTimeDimension ? 'line' : 'number' }; @@ -389,11 +385,10 @@ export default class QueryBuilder extends React.Component { timeDimensions: (newQuery.timeDimensions || []).map((td) => ({ ...td, granularity: undefined })) }; - this.shouldApplyHeuristicOrder = true; - return { ...newState, pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: 'table' }; @@ -408,11 +403,10 @@ export default class QueryBuilder extends React.Component { })) }; - this.shouldApplyHeuristicOrder = true; - return { ...newState, pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, chartType: (newQuery.timeDimensions || []).length ? 'line' : 'number' }; @@ -429,11 +423,10 @@ export default class QueryBuilder extends React.Component { filters: [] }; - this.shouldApplyHeuristicOrder = true; - return { ...newState, pivotConfig: null, + shouldApplyHeuristicOrder: true, query: newQuery, sessionGranularity: null }; @@ -468,6 +461,7 @@ export default class QueryBuilder extends React.Component { return { ...newState, pivotConfig: null, + shouldApplyHeuristicOrder: true, query: { ...query, timeDimensions: [{ ...td, granularity: undefined }]