diff --git a/packages/cubejs-api-gateway/index.js b/packages/cubejs-api-gateway/index.js index 817e54a168b93..b912721a33a51 100644 --- a/packages/cubejs-api-gateway/index.js +++ b/packages/cubejs-api-gateway/index.js @@ -146,6 +146,8 @@ const querySchema = Joi.object().keys({ ungrouped: Joi.boolean() }); +const DateRegex = /^\d\d\d\d-\d\d-\d\d$/; + const normalizeQuery = (query) => { // eslint-disable-next-line no-unused-vars const { error, value } = Joi.validate(query, querySchema); @@ -222,7 +224,13 @@ const normalizeQuery = (query) => { } return { ...td, - dateRange + dateRange: dateRange.map( + (d, i) => ( + i === 0 ? + moment.utc(d).format(d.match(DateRegex) ? 'YYYY-MM-DDT00:00:00.000' : moment.HTML5_FMT.DATETIME_LOCAL_MS) : + moment.utc(d).format(d.match(DateRegex) ? 'YYYY-MM-DDT23:59:59.999' : moment.HTML5_FMT.DATETIME_LOCAL_MS) + ) + ) }; }).concat(regularToTimeDimension) }; diff --git a/packages/cubejs-api-gateway/index.test.js b/packages/cubejs-api-gateway/index.test.js index 2df6e1bbd5145..13615f06342c8 100644 --- a/packages/cubejs-api-gateway/index.test.js +++ b/packages/cubejs-api-gateway/index.test.js @@ -9,7 +9,8 @@ const compilerApi = jest.fn().mockImplementation(() => ({ return { sql: ['SELECT * FROM test', []], aliasNameToMember: { - foo__bar: 'Foo.bar' + foo__bar: 'Foo.bar', + foo__time: 'Foo.time' } }; }, @@ -23,6 +24,8 @@ const compilerApi = jest.fn().mockImplementation(() => ({ }], dimensions: [{ name: 'Foo.id' + }, { + name: 'Foo.time' }] } }]; @@ -75,4 +78,16 @@ describe(`API Gateway`, () => { console.log(res.body); expect(res.body && res.body.data).toStrictEqual([{ 'Foo.bar': 42 }]); }); + + test(`date range padding`, async () => { + const res = await request(app) + .get('/cubejs-api/v1/load?query={"measures":["Foo.bar"],"timeDimensions":[{"dimension":"Foo.time","granularity":"hour","dateRange":["2020-01-01","2020-01-01"]}]}') + .set('Authorization', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M') + .expect(200); + console.log(res.body); + expect(res.body.query.timeDimensions[0].dateRange).toStrictEqual([ + "2020-01-01T00:00:00.000", + "2020-01-01T23:59:59.999" + ]); + }); }); diff --git a/packages/cubejs-client-core/src/ResultSet.js b/packages/cubejs-client-core/src/ResultSet.js index 18d92f5eca4b1..b279a53d2d747 100644 --- a/packages/cubejs-client-core/src/ResultSet.js +++ b/packages/cubejs-client-core/src/ResultSet.js @@ -27,6 +27,8 @@ const TIME_SERIES = { .map(d => d.startOf('isoweek').format('YYYY-MM-DDT00:00:00.000')) }; +const DateRegex = /^\d\d\d\d-\d\d-\d\d$/; + /** * Provides a convenient interface for data manipulation. */ @@ -171,7 +173,9 @@ class ResultSet { if (!dateRange) { return null; } - const padToDay = timeDimension.granularity !== 'minute' && timeDimension.granularity !== 'second'; + const padToDay = timeDimension.dateRange ? + timeDimension.dateRange.find(d => d.match(DateRegex)) : + ['hour', 'minute', 'second'].indexOf(timeDimension.granularity) === -1; const start = moment(dateRange[0]).format(padToDay ? 'YYYY-MM-DDT00:00:00.000' : moment.HTML5_FMT.DATETIME_LOCAL_MS); const end = moment(dateRange[1]).format(padToDay ? 'YYYY-MM-DDT23:59:59.999' : moment.HTML5_FMT.DATETIME_LOCAL_MS); const range = moment.range(start, end); diff --git a/packages/cubejs-client-core/src/ResultSet.test.js b/packages/cubejs-client-core/src/ResultSet.test.js index eaa71bdca4ac1..67ffd5d36f815 100644 --- a/packages/cubejs-client-core/src/ResultSet.test.js +++ b/packages/cubejs-client-core/src/ResultSet.test.js @@ -72,6 +72,22 @@ describe('ResultSet', () => { ]; expect(resultSet.timeSeries(timeDimension)).toEqual(output); }); + + test('it generates array of dates - granularity hour - not full day', () => { + const resultSet = new ResultSet({}); + const timeDimension = { + dateRange: ['2015-01-01T10:30:00.000', '2015-01-01T13:59:00.000'], + granularity: 'hour', + timeDimension: 'Events.time' + }; + const output = [ + '2015-01-01T10:00:00.000', + '2015-01-01T11:00:00.000', + '2015-01-01T12:00:00.000', + '2015-01-01T13:00:00.000' + ]; + expect(resultSet.timeSeries(timeDimension)).toEqual(output); + }); }); describe('normalizePivotConfig', () => {