Skip to content

Commit 9ec443f

Browse files
committed
fix(schema-compiler): Reject pre-agg if measure is unmultiplied in query but multiplied in pre-agg
1 parent c54aa36 commit 9ec443f

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3873,11 +3873,11 @@ export class BaseQuery {
38733873
}
38743874

38753875
// eslint-disable-next-line consistent-return
3876-
preAggregationQueryForSqlEvaluation(cube, preAggregation) {
3876+
preAggregationQueryForSqlEvaluation(cube, preAggregation, context = {}) {
38773877
if (preAggregation.type === 'autoRollup') {
38783878
return this.preAggregations.autoRollupPreAggregationQuery(cube, preAggregation);
38793879
} else if (preAggregation.type === 'rollup') {
3880-
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation);
3880+
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation, context);
38813881
} else if (preAggregation.type === 'originalSql') {
38823882
return this;
38833883
}

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export type PreAggregationForCube = {
5050
references: PreAggregationReferences;
5151
};
5252

53+
export type EvaluateReferencesContext = {
54+
inPreAggEvaluation?: boolean;
55+
};
56+
5357
export type BaseMember = BaseDimension | BaseMeasure | BaseFilter | BaseGroupFilter | BaseSegment;
5458

5559
export type CanUsePreAggregationFn = (references: PreAggregationReferences) => boolean;
@@ -583,12 +587,15 @@ export class PreAggregations {
583587
const dimensionsTrimmed = references
584588
.dimensions
585589
.map(d => CubeSymbols.joinHintFromPath(d).path);
590+
const multipliedMeasuresTrimmed = references
591+
.multipliedMeasures?.map(m => CubeSymbols.joinHintFromPath(m).path);
586592

587593
return {
588594
...references,
589595
dimensions: dimensionsTrimmed,
590596
measures: measuresTrimmed,
591597
timeDimensions: timeDimensionsTrimmed,
598+
multipliedMeasures: multipliedMeasuresTrimmed,
592599
};
593600
}
594601

@@ -723,6 +730,19 @@ export class PreAggregations {
723730
// TODO remove this in favor of matching with join path
724731
const referencesTrimmed = trimmedReferences(references);
725732

733+
// Even if there are no multiplied measures in the query (because no multiplier dimensions are requested)
734+
// but the same measures are multiplied in the pre-aggregation, we can't use pre-aggregation
735+
// for such queries.
736+
if (referencesTrimmed.multipliedMeasures) {
737+
const backAliasMultipliedMeasures = backAlias(referencesTrimmed.multipliedMeasures);
738+
739+
if (transformedQuery.leafMeasures.some(m => referencesTrimmed.multipliedMeasures.includes(m)) ||
740+
transformedQuery.measures.some(m => backAliasMultipliedMeasures.includes(m))
741+
) {
742+
return false;
743+
}
744+
}
745+
726746
const dimensionsMatch = (dimensions, doBackAlias) => R.all(
727747
d => (
728748
doBackAlias ?
@@ -1194,11 +1214,11 @@ export class PreAggregations {
11941214
);
11951215
}
11961216

1197-
public rollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1217+
public rollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition, context: EvaluateReferencesContext = {}): BaseQuery {
11981218
// `this.evaluateAllReferences` will retain not only members, but their join path as well, and pass join hints
11991219
// to subquery. Otherwise, members in subquery would regenerate new join tree from clean state,
12001220
// and it can be different from expected by join path in pre-aggregation declaration
1201-
const references = this.evaluateAllReferences(cube, aggregation);
1221+
const references = this.evaluateAllReferences(cube, aggregation, null, context);
12021222
const cubeQuery = this.query.newSubQueryForCube(cube, {});
12031223
return this.query.newSubQueryForCube(cube, {
12041224
rowLimit: null,
@@ -1226,7 +1246,7 @@ export class PreAggregations {
12261246
});
12271247
}
12281248

1229-
public autoRollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1249+
public autoRollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition): BaseQuery {
12301250
return this.query.newSubQueryForCube(
12311251
cube,
12321252
{
@@ -1267,13 +1287,18 @@ export class PreAggregations {
12671287
.toLowerCase();
12681288
}
12691289

1270-
private evaluateAllReferences(cube: string, aggregation: PreAggregationDefinition, preAggregationName: string | null = null): PreAggregationReferences {
1290+
private evaluateAllReferences(cube: string, aggregation: PreAggregationDefinition, preAggregationName: string | null = null, context: EvaluateReferencesOptions = {}): PreAggregationReferences {
12711291
// TODO build a join tree for all references, so they would always include full join path
12721292
// Even for preaggregation references without join path
12731293
// It is necessary to be able to match query and preaggregation based on full join tree
12741294

12751295
const evaluateReferences = () => {
12761296
const references = this.query.cubeEvaluator.evaluatePreAggregationReferences(cube, aggregation);
1297+
if (!context.inPreAggEvaluation) {
1298+
const preAggQuery = this.query.preAggregationQueryForSqlEvaluation(cube, aggregation, { inPreAggEvaluation: true });
1299+
const aggregateMeasures = preAggQuery?.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true });
1300+
references.multipliedMeasures = aggregateMeasures?.multipliedMeasures?.map(m => m.measure);
1301+
}
12771302
if (aggregation.type === 'rollupLambda') {
12781303
if (references.rollups.length > 0) {
12791304
const [firstLambdaCube] = this.query.cubeEvaluator.parsePath('preAggregations', references.rollups[0]);

packages/cubejs-schema-compiler/src/compiler/CubeEvaluator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export type PreAggregationReferences = {
121121
measures: Array<string>,
122122
timeDimensions: Array<PreAggregationTimeDimensionReference>,
123123
rollups: Array<string>,
124+
multipliedMeasures?: Array<string>,
124125
};
125126

126127
export type PreAggregationInfo = {

0 commit comments

Comments
 (0)