Skip to content

Commit e236079

Browse files
authored
fix: Match additive pre-aggregations with missing members for views and proxy members (#7433)
1 parent e2c4880 commit e236079

File tree

2 files changed

+128
-12
lines changed

2 files changed

+128
-12
lines changed

packages/cubejs-schema-compiler/src/adapter/PreAggregations.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ export class PreAggregations {
533533
? transformedQuery.timeDimensions
534534
: transformedQuery.sortedTimeDimensions;
535535

536+
const backAliasMeasures = backAlias(references.measures);
537+
const backAliasSortedDimensions = backAlias(references.sortedDimensions || references.dimensions);
538+
const backAliasDimensions = backAlias(references.dimensions);
536539
return ((
537540
transformedQuery.hasNoTimeDimensionsWithoutGranularity
538541
) && (
@@ -545,13 +548,13 @@ export class PreAggregations {
545548
) && (
546549
filterDimensionsSingleValueEqual &&
547550
references.dimensions.length === filterDimensionsSingleValueEqual.size &&
548-
R.all(d => filterDimensionsSingleValueEqual.has(d), backAlias(references.dimensions)) ||
551+
R.all(d => filterDimensionsSingleValueEqual.has(d), backAliasDimensions) ||
549552
transformedQuery.allFiltersWithinSelectedDimensions &&
550-
R.equals(backAlias(references.sortedDimensions || references.dimensions), transformedQuery.sortedDimensions)
553+
R.equals(backAliasSortedDimensions, transformedQuery.sortedDimensions)
551554
) && (
552-
R.all(m => backAlias(references.measures).indexOf(m) !== -1, transformedQuery.measures) ||
555+
R.all(m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.measures) ||
553556
// TODO do we need backAlias here?
554-
R.all(m => backAlias(references.measures).indexOf(m) !== -1, transformedQuery.leafMeasures)
557+
R.all(m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.leafMeasures)
555558
));
556559
};
557560

@@ -619,33 +622,39 @@ export class PreAggregations {
619622
? transformedQuery.ownedTimeDimensionsAsIs.map(expandTimeDimension)
620623
: transformedQuery.ownedTimeDimensionsWithRollupGranularity.map(expandTimeDimension);
621624

622-
const dimensionsMatch = (dimensions) => R.all(
625+
const dimensionsMatch = (dimensions, doBackAlias) => R.all(
623626
d => (
624-
references.sortedDimensions ||
625-
references.dimensions
627+
doBackAlias ?
628+
backAlias(references.sortedDimensions || references.dimensions) :
629+
(references.sortedDimensions || references.dimensions)
626630
).indexOf(d) !== -1,
627631
dimensions
628632
);
629633

630-
const timeDimensionsMatch = (timeDimensionsList) => R.allPass(
634+
const timeDimensionsMatch = (timeDimensionsList, doBackAlias) => R.allPass(
631635
timeDimensionsList.map(
632636
tds => R.anyPass(tds.map(td => R.contains(td)))
633637
)
634638
)(
635-
references.sortedTimeDimensions ||
636-
sortTimeDimensions(references.timeDimensions)
639+
doBackAlias ?
640+
backAlias(references.sortedTimeDimensions || sortTimeDimensions(references.timeDimensions)) :
641+
(references.sortedTimeDimensions || sortTimeDimensions(references.timeDimensions))
637642
);
638643

644+
const backAliasMeasures = backAlias(references.measures);
639645
return ((
640646
windowGranularityMatches(references)
641647
) && (
642648
R.all(
643649
m => references.measures.indexOf(m) !== -1,
644650
transformedQuery.leafMeasures,
651+
) || R.all(
652+
m => backAliasMeasures.indexOf(m) !== -1,
653+
transformedQuery.measures,
645654
)
646655
) && (
647-
dimensionsMatch(transformedQuery.sortedDimensions) && timeDimensionsMatch(queryTimeDimensionsList) ||
648-
dimensionsMatch(transformedQuery.ownedDimensions) && timeDimensionsMatch(ownedQueryTimeDimensionsList)
656+
dimensionsMatch(transformedQuery.sortedDimensions, true) && timeDimensionsMatch(queryTimeDimensionsList, true) ||
657+
dimensionsMatch(transformedQuery.ownedDimensions, false) && timeDimensionsMatch(ownedQueryTimeDimensionsList, false)
649658
));
650659
};
651660

packages/cubejs-schema-compiler/test/integration/postgres/pre-aggregations.test.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ describe('PreAggregations', () => {
8888
type: 'string',
8989
sql: 'source'
9090
},
91+
sourceAndId: {
92+
type: 'string',
93+
sql: \`\${source} || '_' || \${id}\`,
94+
},
9195
createdAt: {
9296
type: 'time',
9397
sql: 'created_at'
@@ -220,6 +224,12 @@ describe('PreAggregations', () => {
220224
granularity: 'hour',
221225
partitionGranularity: 'month'
222226
},
227+
sourceAndIdRollup: {
228+
measures: [count],
229+
dimensions: [sourceAndId, source],
230+
timeDimension: createdAt,
231+
granularity: 'hour',
232+
}
223233
}
224234
})
225235
@@ -749,6 +759,103 @@ describe('PreAggregations', () => {
749759
});
750760
}));
751761

762+
it('non-leaf additive measure', () => compiler.compile().then(() => {
763+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
764+
measures: [
765+
'visitors_view.count'
766+
],
767+
dimensions: ['visitors_view.sourceAndId'],
768+
timezone: 'America/Los_Angeles',
769+
order: [{
770+
id: 'visitors_view.sourceAndId'
771+
}],
772+
preAggregationsSchema: ''
773+
});
774+
775+
const queryAndParams = query.buildSqlAndParams();
776+
console.log(queryAndParams);
777+
const preAggregationsDescription = query.preAggregations?.preAggregationsDescription();
778+
console.log(preAggregationsDescription);
779+
expect((<any>preAggregationsDescription)[0].loadSql[0]).toMatch(/visitors_source_and_id_rollup/);
780+
781+
return dbRunner.evaluateQueryWithPreAggregations(query).then(res => {
782+
expect(res).toEqual(
783+
[
784+
{
785+
visitors_view__count: '1',
786+
visitors_view__source_and_id: 'google_3'
787+
},
788+
{
789+
visitors_view__count: '1',
790+
visitors_view__source_and_id: 'some_1'
791+
},
792+
{
793+
visitors_view__count: '1',
794+
visitors_view__source_and_id: 'some_2'
795+
},
796+
{
797+
visitors_view__count: '3',
798+
visitors_view__source_and_id: null
799+
}
800+
]
801+
);
802+
});
803+
}));
804+
805+
it('non-leaf additive measure with time dimension', () => compiler.compile().then(() => {
806+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
807+
measures: [
808+
'visitors_view.count'
809+
],
810+
dimensions: ['visitors_view.sourceAndId'],
811+
timezone: 'America/Los_Angeles',
812+
timeDimensions: [{
813+
dimension: 'visitors_view.signedUpAt',
814+
granularity: 'day',
815+
dateRange: ['2017-01-01', '2017-01-30']
816+
}],
817+
order: [{
818+
id: 'visitors_view.createdAt',
819+
}, {
820+
id: 'visitors_view.sourceAndId'
821+
}],
822+
preAggregationsSchema: ''
823+
});
824+
825+
const queryAndParams = query.buildSqlAndParams();
826+
console.log(queryAndParams);
827+
const preAggregationsDescription = query.preAggregations?.preAggregationsDescription();
828+
console.log(preAggregationsDescription);
829+
expect((<any>preAggregationsDescription)[0].loadSql[0]).toMatch(/visitors_source_and_id_rollup/);
830+
831+
return dbRunner.evaluateQueryWithPreAggregations(query).then(res => {
832+
expect(res).toEqual(
833+
[
834+
{
835+
visitors_view__count: '1',
836+
visitors_view__signed_up_at_day: '2017-01-05T00:00:00.000Z',
837+
visitors_view__source_and_id: 'google_3'
838+
},
839+
{
840+
visitors_view__count: '1',
841+
visitors_view__signed_up_at_day: '2017-01-02T00:00:00.000Z',
842+
visitors_view__source_and_id: 'some_1'
843+
},
844+
{
845+
visitors_view__count: '1',
846+
visitors_view__signed_up_at_day: '2017-01-04T00:00:00.000Z',
847+
visitors_view__source_and_id: 'some_2'
848+
},
849+
{
850+
visitors_view__count: '2',
851+
visitors_view__signed_up_at_day: '2017-01-06T00:00:00.000Z',
852+
visitors_view__source_and_id: null
853+
}
854+
]
855+
);
856+
});
857+
}));
858+
752859
it('inherited original sql', () => compiler.compile().then(() => {
753860
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
754861
measures: [

0 commit comments

Comments
 (0)