From 861db106311ad58a4dc47a2f8ce13722c331f107 Mon Sep 17 00:00:00 2001 From: "Alex.V" Date: Mon, 20 Jul 2020 23:29:30 +0300 Subject: [PATCH] fix: preserve order of sorted data (#870) --- packages/cubejs-client-core/src/ResultSet.js | 29 ++++++++--- .../src/tests/ResultSet.test.js | 52 +++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/packages/cubejs-client-core/src/ResultSet.js b/packages/cubejs-client-core/src/ResultSet.js index 5541aad366976..138d09887b260 100644 --- a/packages/cubejs-client-core/src/ResultSet.js +++ b/packages/cubejs-client-core/src/ResultSet.js @@ -26,6 +26,24 @@ const TIME_SERIES = { const DateRegex = /^\d\d\d\d-\d\d-\d\d$/; const LocalDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z?$/; +const groupByToPairs = (keyFn) => { + const acc = new Map(); + + return (data) => { + data.forEach((row) => { + const key = keyFn(row); + + if (!acc.has(key)) { + acc.set(key, []); + } + + acc.get(key).push(row); + }); + + return Array.from(acc.entries()); + }; +}; + class ResultSet { constructor(loadResponse, options = {}) { this.loadResponse = loadResponse; @@ -233,7 +251,7 @@ class ResultSet { pivot(pivotConfig) { pivotConfig = this.normalizePivotConfig(pivotConfig); - let groupByXAxis = groupBy(({ xValues }) => this.axisValuesString(xValues)); + let groupByXAxis = groupByToPairs(({ xValues }) => this.axisValuesString(xValues)); // eslint-disable-next-line no-unused-vars let measureValue = (row, measure, xValues) => row[measure]; @@ -255,8 +273,8 @@ class ResultSet { ({ xValues }) => moment(xValues[0]).format(moment.HTML5_FMT.DATETIME_LOCAL_MS), rows ); - return series.map(d => ({ [d]: byXValues[d] || [{ xValues: [d], row: {} }] })) - .reduce((a, b) => Object.assign(a, b), {}); + return toPairs(series.map(d => ({ [d]: byXValues[d] || [{ xValues: [d], row: {} }] })) + .reduce((a, b) => Object.assign(a, b), {})); }; // eslint-disable-next-line no-unused-vars @@ -267,8 +285,7 @@ class ResultSet { const xGrouped = pipe( map(row => this.axisValues(pivotConfig.x)(row).map(xValues => ({ xValues, row }))), unnest, - groupByXAxis, - toPairs + groupByXAxis )(this.timeDimensionBackwardCompatibleData()); const allYValues = pipe( @@ -284,7 +301,7 @@ class ResultSet { )(xGrouped); // eslint-disable-next-line no-unused-vars - return xGrouped.map(([xValuesString, rows]) => { + return xGrouped.map(([, rows]) => { const { xValues } = rows[0]; const yGrouped = pipe( map(({ row }) => this.axisValues(pivotConfig.y)(row).map(yValues => ({ yValues, row }))), diff --git a/packages/cubejs-client-core/src/tests/ResultSet.test.js b/packages/cubejs-client-core/src/tests/ResultSet.test.js index 2f3f6cffeca96..2004545280011 100644 --- a/packages/cubejs-client-core/src/tests/ResultSet.test.js +++ b/packages/cubejs-client-core/src/tests/ResultSet.test.js @@ -912,5 +912,57 @@ describe('ResultSet', () => { { 'Orders.createdAt': '2020-01-10T13:50:05.000' } ]); }); + + test('order is preserved', () => { + const resultSet = new ResultSet({ + query: { + measures: ['User.total'], + dimensions: ['User.visits'], + filters: [], + timezone: 'UTC' + }, + data: [ + { + 'User.total': 1, + 'User.visits': 1 + }, + { + 'User.total': 15, + 'User.visits': 0.9 + }, + { + 'User.total': 20, + 'User.visits': 0.7 + }, + { + 'User.total': 10, + 'User.visits': 0 + }, + ], + annotation: { + measures: { + 'User.total': {} + }, + dimensions: { + 'User.visits': { + title: 'User Visits', + shortTitle: 'Visits', + type: 'number' + } + }, + segments: {}, + timeDimensions: {} + } + }); + + expect(resultSet.pivot()).toEqual( + [ + { xValues: [1], yValuesArray: [[['User.total'], 1]] }, + { xValues: [0.9], yValuesArray: [[['User.total'], 15]] }, + { xValues: [0.7], yValuesArray: [[['User.total'], 20]] }, + { xValues: [0], yValuesArray: [[['User.total'], 10]] }, + ] + ); + }); }); });