Skip to content

Commit 9698ca6

Browse files
committed
fix(schema-compiler): Handle pre-aggregations matching in presence of join paths
1 parent 2afa4de commit 9698ca6

File tree

2 files changed

+319
-34
lines changed

2 files changed

+319
-34
lines changed

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

+61-20
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,13 @@ export class PreAggregations {
430430
};
431431
}
432432

433+
/**
434+
*
435+
* @param query
436+
* @param members
437+
* @param {Map<string, Array<string>>} cubeToJoinPrefix
438+
* @returns {Array<string>}
439+
*/
433440
static ownedMembers(query, members) {
434441
return R.pipe(R.uniq, R.sortBy(R.identity))(
435442
query
@@ -495,6 +502,33 @@ export class PreAggregations {
495502
// query can have same members as pre-agg, but different calculated join path
496503
// `refs` will come from preagg references, and would contain full join paths
497504

505+
// TODO remove this in favor of matching with join path
506+
/**
507+
* @param {PreAggregationReferences} references
508+
* @returns {PreAggregationReferences}
509+
*/
510+
function trimmedReferences(references) {
511+
const timeDimensionsTrimmed = references
512+
.timeDimensions
513+
.map(td => ({
514+
...td,
515+
dimension: CubeSymbols.joinHintFromPath(td.dimension).path,
516+
}));
517+
const measuresTrimmed = references
518+
.measures
519+
.map(m => CubeSymbols.joinHintFromPath(m).path);
520+
const dimensionsTrimmed = references
521+
.dimensions
522+
.map(d => CubeSymbols.joinHintFromPath(d).path);
523+
524+
return {
525+
...references,
526+
dimensions: dimensionsTrimmed,
527+
measures: measuresTrimmed,
528+
timeDimensions: timeDimensionsTrimmed,
529+
};
530+
}
531+
498532
/**
499533
* Returns an array of 2-elements arrays with the dimension and granularity
500534
* sorted by the concatenated dimension + granularity key.
@@ -534,18 +568,19 @@ export class PreAggregations {
534568

535569
/**
536570
* Determine whether pre-aggregation can be used or not.
537-
* @param {*} references
571+
* @param {PreAggregationReferences} references
538572
* @returns {boolean}
539573
*/
540574
const canUsePreAggregationNotAdditive = (references) => {
541-
const refTimeDimensions =
542-
backAlias(references.sortedTimeDimensions || sortTimeDimensions(references.timeDimensions));
575+
// TODO remove this in favor of matching with join path
576+
const referencesTrimmed = trimmedReferences(references);
577+
578+
const refTimeDimensions = backAlias(sortTimeDimensions(referencesTrimmed.timeDimensions));
543579
const qryTimeDimensions = references.allowNonStrictDateRangeMatch
544580
? transformedQuery.timeDimensions
545581
: transformedQuery.sortedTimeDimensions;
546-
const backAliasMeasures = backAlias(references.measures);
547-
const backAliasSortedDimensions = backAlias(references.sortedDimensions || references.dimensions);
548-
const backAliasDimensions = backAlias(references.dimensions);
582+
const backAliasMeasures = backAlias(referencesTrimmed.measures);
583+
const backAliasDimensions = backAlias(referencesTrimmed.dimensions);
549584
return ((
550585
transformedQuery.hasNoTimeDimensionsWithoutGranularity
551586
) && (
@@ -557,10 +592,10 @@ export class PreAggregations {
557592
R.equals(transformedQuery.timeDimensions, refTimeDimensions)
558593
) && (
559594
filterDimensionsSingleValueEqual &&
560-
references.dimensions.length === filterDimensionsSingleValueEqual.size &&
595+
referencesTrimmed.dimensions.length === filterDimensionsSingleValueEqual.size &&
561596
R.all(d => filterDimensionsSingleValueEqual.has(d), backAliasDimensions) ||
562597
transformedQuery.allFiltersWithinSelectedDimensions &&
563-
R.equals(backAliasSortedDimensions, transformedQuery.sortedDimensions)
598+
R.equals(backAliasDimensions, transformedQuery.sortedDimensions)
564599
) && (
565600
R.all(m => backAliasMeasures.indexOf(m) !== -1, transformedQuery.measures) ||
566601
// TODO do we need backAlias here?
@@ -581,16 +616,15 @@ export class PreAggregations {
581616

582617
/**
583618
* Determine whether time dimensions match to the window granularity or not.
584-
* @param {*} references
619+
* @param {PreAggregationReferences} references
585620
* @returns {boolean}
586621
*/
587622
const windowGranularityMatches = (references) => {
588623
if (!transformedQuery.windowGranularity) {
589624
return true;
590625
}
591-
const sortedTimeDimensions =
592-
references.sortedTimeDimensions ||
593-
sortTimeDimensions(references.timeDimensions);
626+
// Beware that sortedTimeDimensions contain full join paths
627+
const sortedTimeDimensions = sortTimeDimensions(references.timeDimensions);
594628

595629
return sortedTimeDimensions
596630
.map(td => expandGranularity(td[0], transformedQuery.windowGranularity))
@@ -620,7 +654,7 @@ export class PreAggregations {
620654
/**
621655
* Determine whether pre-aggregation can be used or not.
622656
* TODO: revisit cumulative leaf measure matches.
623-
* @param {*} references
657+
* @param {PreAggregationReferences} references
624658
* @returns {boolean}
625659
*/
626660
const canUsePreAggregationLeafMeasureAdditive = (references) => {
@@ -636,11 +670,14 @@ export class PreAggregations {
636670
? transformedQuery.ownedTimeDimensionsAsIs.map(expandTimeDimension)
637671
: transformedQuery.ownedTimeDimensionsWithRollupGranularity.map(expandTimeDimension);
638672

673+
// TODO remove this in favor of matching with join path
674+
const referencesTrimmed = trimmedReferences(references);
675+
639676
const dimensionsMatch = (dimensions, doBackAlias) => R.all(
640677
d => (
641678
doBackAlias ?
642-
backAlias(references.sortedDimensions || references.dimensions) :
643-
(references.sortedDimensions || references.dimensions)
679+
backAlias(referencesTrimmed.dimensions) :
680+
(referencesTrimmed.dimensions)
644681
).indexOf(d) !== -1,
645682
dimensions
646683
);
@@ -657,13 +694,13 @@ export class PreAggregations {
657694
)
658695
)(
659696
doBackAlias ?
660-
backAlias(references.sortedTimeDimensions || sortTimeDimensions(references.timeDimensions)) :
661-
(references.sortedTimeDimensions || sortTimeDimensions(references.timeDimensions))
697+
backAlias(sortTimeDimensions(referencesTrimmed.timeDimensions)) :
698+
(sortTimeDimensions(referencesTrimmed.timeDimensions))
662699
);
663700

664701
if (transformedQuery.ungrouped) {
665702
const allReferenceCubes = R.pipe(R.map(m => (m.dimension || m).split('.')[0]), R.uniq, R.sortBy(R.identity))(
666-
references.measures.concat(references.dimensions).concat(references.timeDimensions)
703+
referencesTrimmed.measures.concat(referencesTrimmed.dimensions).concat(referencesTrimmed.timeDimensions)
667704
);
668705
if (
669706
!R.equals(transformedQuery.sortedAllCubeNames, allReferenceCubes) ||
@@ -675,12 +712,12 @@ export class PreAggregations {
675712
}
676713
}
677714

678-
const backAliasMeasures = backAlias(references.measures);
715+
const backAliasMeasures = backAlias(referencesTrimmed.measures);
679716
return ((
680717
windowGranularityMatches(references)
681718
) && (
682719
R.all(
683-
m => references.measures.indexOf(m) !== -1,
720+
m => referencesTrimmed.measures.indexOf(m) !== -1,
684721
transformedQuery.leafMeasures,
685722
) || R.all(
686723
m => backAliasMeasures.indexOf(m) !== -1,
@@ -1151,6 +1188,10 @@ export class PreAggregations {
11511188
* @returns {PreAggregationReferences}
11521189
*/
11531190
evaluateAllReferences(cube, aggregation, preAggregationName) {
1191+
// TODO build a join tree for all references, so they would always include full join path
1192+
// Even for preaggregation references without join path
1193+
// It is necessary to be able to match query and preaggregation based on full join tree
1194+
11541195
const evaluateReferences = () => {
11551196
const references = this.query.cubeEvaluator.evaluatePreAggregationReferences(cube, aggregation);
11561197
if (aggregation.type === 'rollupLambda') {

0 commit comments

Comments
 (0)