Skip to content

Commit

Permalink
feat: Parse dates on client side (#522) Thanks to @richipargo!
Browse files Browse the repository at this point in the history
* Change default order value

If you don't set a order value on the intial query format
`@cubejs-server/core` doesn't handle empty object

* Add date validation

* update tests

* validate string response values as well
  • Loading branch information
richipargo authored Apr 16, 2020
1 parent 964c6d8 commit 11c1106
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 1 deletion.
15 changes: 14 additions & 1 deletion packages/cubejs-client-core/src/ResultSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const TIME_SERIES = {
};

const DateRegex = /^\d\d\d\d-\d\d-\d\d$/;
const ISO8601_REGEX = /^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;

/**
* Provides a convenient interface for data manipulation.
Expand Down Expand Up @@ -287,12 +288,24 @@ class ResultSet {
* @param pivotConfig
*/
chartPivot(pivotConfig) {
const validate = (value) => {
if (ISO8601_REGEX.test(value)) {
return new Date(value);
} else if (!Number.isNaN(Number.parseFloat(value))) {
return Number.parseFloat(value);
}

return value;
};

return this.pivot(pivotConfig).map(({ xValues, yValuesArray }) => ({
category: this.axisValuesString(xValues, ', '), // TODO deprecated
x: this.axisValuesString(xValues, ', '),
...(
yValuesArray
.map(([yValues, m]) => ({ [this.axisValuesString(yValues, ', ')]: m && Number.parseFloat(m) }))
.map(([yValues, m]) => ({
[this.axisValuesString(yValues, ', ')]: m && validate(m),
}))
.reduce((a, b) => Object.assign(a, b), {})
)
}));
Expand Down
212 changes: 212 additions & 0 deletions packages/cubejs-client-core/src/ResultSet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,218 @@ describe('ResultSet', () => {
});
});

describe('chartPivot', () => {
test('String field', () => {
const resultSet = new ResultSet({
query: {
measures: ['Foo.count'],
dimensions: ['Foo.name'],
filters: [],
timezone: 'UTC',
timeDimensions: [],
},
data: [{
'Foo.name': 'Name 1',
'Foo.count': 'Some string',
}],
lastRefreshTime: '2020-03-18T13:41:04.436Z',
usedPreAggregations: {},
annotation: {
measures: {
'Foo.count': {
title: 'Foo Count',
shortTitle: 'Count',
type: 'number',
},
},
dimensions: {
'Foo.name': {
title: 'Foo Name',
shortTitle: 'Name',
type: 'string',
},
},
segments: {},
timeDimensions: {},
},
});

expect(resultSet.chartPivot()).toEqual([{
x: 'Name 1',
category: 'Name 1',
'Foo.count': 'Some string',
}]);
});

test('Null field', () => {
const resultSet = new ResultSet({
query: {
measures: ['Foo.count'],
dimensions: ['Foo.name'],
filters: [],
timezone: 'UTC',
timeDimensions: [],
},
data: [{
'Foo.name': 'Name 1',
'Foo.count': null,
}],
lastRefreshTime: '2020-03-18T13:41:04.436Z',
usedPreAggregations: {},
annotation: {
measures: {
'Foo.count': {
title: 'Foo Count',
shortTitle: 'Count',
type: 'number',
},
},
dimensions: {
'Foo.name': {
title: 'Foo Name',
shortTitle: 'Name',
type: 'string',
},
},
segments: {},
timeDimensions: {},
},
});

expect(resultSet.chartPivot()).toEqual([{
x: 'Name 1',
category: 'Name 1',
'Foo.count': null,
}]);
});

test('Empty field', () => {
const resultSet = new ResultSet({
query: {
measures: ['Foo.count'],
dimensions: ['Foo.name'],
filters: [],
timezone: 'UTC',
timeDimensions: [],
},
data: [{
'Foo.name': 'Name 1',
'Foo.count': undefined,
}],
lastRefreshTime: '2020-03-18T13:41:04.436Z',
usedPreAggregations: {},
annotation: {
measures: {
'Foo.count': {
title: 'Foo Count',
shortTitle: 'Count',
type: 'number',
},
},
dimensions: {
'Foo.name': {
title: 'Foo Name',
shortTitle: 'Name',
type: 'string',
},
},
segments: {},
timeDimensions: {},
},
});

expect(resultSet.chartPivot()).toEqual([{
x: 'Name 1',
category: 'Name 1',
'Foo.count': undefined,
}]);
});

test('Number field', () => {
const resultSet = new ResultSet({
query: {
measures: ['Foo.count'],
dimensions: ['Foo.name'],
filters: [],
timezone: 'UTC',
timeDimensions: [],
},
data: [{
'Foo.name': 'Name 1',
'Foo.count': 10,
}],
lastRefreshTime: '2020-03-18T13:41:04.436Z',
usedPreAggregations: {},
annotation: {
measures: {
'Foo.count': {
title: 'Foo Count',
shortTitle: 'Count',
type: 'number',
},
},
dimensions: {
'Foo.name': {
title: 'Foo Name',
shortTitle: 'Name',
type: 'string',
},
},
segments: {},
timeDimensions: {},
},
});

expect(resultSet.chartPivot()).toEqual([{
x: 'Name 1',
category: 'Name 1',
'Foo.count': 10,
}]);
});

test('time field results', () => {
const resultSet = new ResultSet({
query: {
measures: ['Foo.latestRun'],
dimensions: ['Foo.name'],
filters: [],
timezone: 'UTC',
timeDimensions: [],
},
data: [{
'Foo.name': 'Name 1',
'Foo.latestRun': '2020-03-11T18:06:09.403Z',
}],
lastRefreshTime: '2020-03-18T13:41:04.436Z',
usedPreAggregations: {},
annotation: {
measures: {
'Foo.latestRun': {
title: 'Foo Latest Run',
shortTitle: 'Latest Run',
type: 'number',
},
},
dimensions: {
'Foo.name': {
title: 'Foo Name',
shortTitle: 'Name',
type: 'string',
},
},
segments: {},
timeDimensions: {},
},
});

expect(resultSet.chartPivot()).toEqual([{
x: 'Name 1',
category: 'Name 1',
'Foo.latestRun': new Date('2020-03-11T18:06:09.403Z'),
}]);
});
});

describe('normalizePivotConfig', () => {
test('fills missing x, y', () => {
const resultSet = new ResultSet({
Expand Down

0 comments on commit 11c1106

Please sign in to comment.