From 07d00f8bdbbc9f0e98bfc342903c9d7e8e6f2e39 Mon Sep 17 00:00:00 2001 From: Pavel Tiunov Date: Sun, 28 Jun 2020 22:43:43 -0700 Subject: [PATCH] fix: Querying empty Postgres table with 'time' dimension in a cube results in null value Fixes #639 --- .../test/PreAggregationsTest.js | 52 +++++++++++++++++++ .../core/RefreshScheduler.js | 8 ++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-schema-compiler/test/PreAggregationsTest.js b/packages/cubejs-schema-compiler/test/PreAggregationsTest.js index aacf9ded4be38..0de41bc44af89 100644 --- a/packages/cubejs-schema-compiler/test/PreAggregationsTest.js +++ b/packages/cubejs-schema-compiler/test/PreAggregationsTest.js @@ -204,6 +204,19 @@ describe('PreAggregations', function test() { incremental: true, updateWindow: '1 day' } + }, + emptyPartitioned: { + type: 'rollup', + measureReferences: [count], + timeDimensionReference: EmptyHourVisitors.createdAt, + granularity: 'hour', + partitionGranularity: 'month', + scheduledRefresh: true, + refreshKey: { + every: '1 hour', + incremental: true, + updateWindow: '1 day' + } } } }) @@ -245,6 +258,11 @@ describe('PreAggregations', function test() { } } }) + + cube('EmptyHourVisitors', { + extends: EveryHourVisitors, + sql: \`select v.* from \${visitors.sql()} v where created_at < '2000-01-01'\` + }) `); function replaceTableName(query, preAggregation, suffix) { @@ -536,6 +554,40 @@ describe('PreAggregations', function test() { }); }); + it('empty scheduled refresh', () => { + return compiler.compile().then(async () => { + const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: [ + 'visitor_checkins.count' + ], + timeDimensions: [{ + dimension: 'EmptyHourVisitors.createdAt', + granularity: 'hour', + dateRange: ['2017-01-01', '2017-01-25'] + }], + timezone: 'UTC', + order: [{ + id: 'EmptyHourVisitors.createdAt' + }], + preAggregationsSchema: '' + }); + + const preAggregations = cubeEvaluator.scheduledPreAggregations(); + const partitionedPreAgg = + preAggregations.find(p => p.preAggregationName === 'emptyPartitioned' && p.cube === 'visitor_checkins'); + + const minMaxQueries = query.preAggregationStartEndQueries('visitor_checkins', partitionedPreAgg.preAggregation); + + console.log(minMaxQueries); + + const res = await dbRunner.testQueries(minMaxQueries); + + res.should.be.deepEqual( + [{ max: null }] + ); + }); + }); + it('mutable partition default refreshKey', () => { return compiler.compile().then(() => { const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { diff --git a/packages/cubejs-server-core/core/RefreshScheduler.js b/packages/cubejs-server-core/core/RefreshScheduler.js index f3fe69848edf4..78186528ed541 100644 --- a/packages/cubejs-server-core/core/RefreshScheduler.js +++ b/packages/cubejs-server-core/core/RefreshScheduler.js @@ -31,12 +31,18 @@ class RefreshScheduler { return data[0] && data[0][Object.keys(data[0])[0]]; }; + const dateRange = [extractDate(startDate), extractDate(endDate)]; + if (!dateRange[0] || !dateRange[1]) { + // Empty table. Nothing to refresh. + return []; + } + const baseQuery = { ...queryingOptions, ...preAggregation.references, timeDimensions: [{ ...preAggregation.references.timeDimensions[0], - dateRange: [extractDate(startDate), extractDate(endDate)] + dateRange }] }; const partitionQuery = compilerApi.createQuery(compilers, dbType, baseQuery);