@@ -92,6 +92,11 @@ export type FullPreAggregationDescription = any;
9292 */
9393export type TransformedQuery = any ;
9494
95+ type BuildRollupJoinResult = {
96+ rollupJoin : RollupJoin ;
97+ existingJoins : JoinEdgeWithMembers [ ] ;
98+ } ;
99+
95100export class PreAggregations {
96101 private readonly query : BaseQuery ;
97102
@@ -521,18 +526,7 @@ export class PreAggregations {
521526 filterDimensionsSingleValueEqual =
522527 allValuesEq1 ( filterDimensionsSingleValueEqual ) ? new Set ( filterDimensionsSingleValueEqual ?. keys ( ) ) : null ;
523528
524- // Build reverse query joins map, which is used for
525- // rollupLambda and rollupJoin pre-aggs matching later
526- const joinsMap : Record < string , string > = { } ;
527- if ( query . join ) {
528- for ( const j of query . join . joins ) {
529- joinsMap [ j . to ] = j . from ;
530- }
531- }
532-
533529 return {
534- joinGraphRoot : query . join ?. root ,
535- joinsMap,
536530 sortedDimensions,
537531 sortedTimeDimensions,
538532 timeDimensions,
@@ -651,16 +645,6 @@ export class PreAggregations {
651645 transformedQuery . allBackAliasMembers [ r ] || r
652646 ) ) ;
653647
654- const buildPath = ( cube : string ) : string [ ] => {
655- const path = [ cube ] ;
656- const parentMap = transformedQuery . joinsMap ;
657- while ( parentMap [ cube ] ) {
658- cube = parentMap [ cube ] ;
659- path . push ( cube ) ;
660- }
661- return path . reverse ( ) ;
662- } ;
663-
664648 /**
665649 * Determine whether pre-aggregation can be used or not.
666650 */
@@ -669,37 +653,9 @@ export class PreAggregations {
669653 ? transformedQuery . timeDimensions
670654 : transformedQuery . sortedTimeDimensions ;
671655
672- let dimsToMatch : string [ ] ;
673- let measToMatch : string [ ] ;
674- let timeDimsToMatch : PreAggregationTimeDimensionReference [ ] ;
675-
676- if ( references . rollups . length > 0 ) {
677- // In 'rollupJoin' / 'rollupLambda' pre-aggregations fullName members will be empty, because there are
678- // no connections in the joinTree between cubes from different datasources
679- // but joinGraph of the query has all the connections, necessary for serving the query,
680- // so we use this information to complete the full paths of members from the root of the query
681- // up to the pre-agg cube.
682- // We use references from the underlying pre-aggregations, filtered with members existing in the root
683- // pre-aggregation itself.
684-
685- dimsToMatch = references . rollupsReferences
686- . flatMap ( rolRef => rolRef . fullNameDimensions )
687- . filter ( d => references . dimensions . some ( rd => d . endsWith ( rd ) ) ) ;
688- timeDimsToMatch = references . rollupsReferences
689- . flatMap ( rolRef => rolRef . fullNameTimeDimensions )
690- . filter ( d => references . timeDimensions . some ( rd => d . dimension . endsWith ( rd . dimension ) ) ) ;
691- measToMatch = references . rollupsReferences
692- . flatMap ( rolRef => rolRef . fullNameMeasures )
693- . filter ( m => references . measures . some ( rm => m . endsWith ( rm ) ) ) ;
694- } else {
695- dimsToMatch = references . fullNameDimensions ;
696- timeDimsToMatch = references . fullNameTimeDimensions ;
697- measToMatch = references . fullNameMeasures ;
698- }
699-
700- const refTimeDimensions = backAlias ( sortTimeDimensions ( timeDimsToMatch ) ) ;
701- const backAliasMeasures = backAlias ( measToMatch ) ;
702- const backAliasDimensions = backAlias ( dimsToMatch ) ;
656+ const refTimeDimensions = backAlias ( sortTimeDimensions ( references . fullNameTimeDimensions ) ) ;
657+ const backAliasMeasures = backAlias ( references . fullNameMeasures ) ;
658+ const backAliasDimensions = backAlias ( references . fullNameDimensions ) ;
703659 return ( (
704660 transformedQuery . hasNoTimeDimensionsWithoutGranularity
705661 ) && (
@@ -716,9 +672,9 @@ export class PreAggregations {
716672 transformedQuery . allFiltersWithinSelectedDimensions &&
717673 R . equals ( backAliasDimensions , transformedQuery . sortedDimensions )
718674 ) && (
719- R . all ( m => backAliasMeasures . indexOf ( m ) !== - 1 , transformedQuery . measures ) ||
675+ R . all ( m => backAliasMeasures . includes ( m ) , transformedQuery . measures ) ||
720676 // TODO do we need backAlias here?
721- R . all ( m => backAliasMeasures . indexOf ( m ) !== - 1 , transformedQuery . leafMeasures )
677+ R . all ( m => backAliasMeasures . includes ( m ) , transformedQuery . leafMeasures )
722678 ) ) ;
723679 } ;
724680
@@ -790,36 +746,8 @@ export class PreAggregations {
790746 }
791747 }
792748
793- let dimsToMatch : string [ ] ;
794- let timeDimsToMatch : PreAggregationTimeDimensionReference [ ] ;
795-
796- if ( references . rollups . length > 0 ) {
797- // In 'rollupJoin' / 'rollupLambda' pre-aggregations fullName members will be empty, because there are
798- // no connections in the joinTree between cubes from different datasources
799- // but joinGraph of the query has all the connections, necessary for serving the query,
800- // so we use this information to complete the full paths of members from the root of the query
801- // up to the pre-agg cube.
802- // We use references from the underlying pre-aggregations, filtered with members existing in the root
803- // pre-aggregation itself.
804-
805- dimsToMatch = references . rollupsReferences
806- . flatMap ( rolRef => rolRef . fullNameDimensions )
807- . filter ( d => references . dimensions . some ( rd => d . endsWith ( rd ) ) )
808- . map ( d => {
809- const [ cube , ...restPath ] = d . split ( '.' ) ;
810- if ( cube === transformedQuery . joinGraphRoot ) {
811- return d ;
812- }
813- const path = buildPath ( cube ) ;
814- return `${ path . join ( '.' ) } .${ restPath . join ( '.' ) } ` ;
815- } ) ;
816- timeDimsToMatch = references . rollupsReferences
817- . flatMap ( rolRef => rolRef . fullNameTimeDimensions )
818- . filter ( d => references . timeDimensions . some ( rd => d . dimension . endsWith ( rd . dimension ) ) ) ;
819- } else {
820- dimsToMatch = references . fullNameDimensions ;
821- timeDimsToMatch = references . fullNameTimeDimensions ;
822- }
749+ const dimsToMatch = references . fullNameDimensions ;
750+ const timeDimsToMatch = references . fullNameTimeDimensions ;
823751
824752 const dimensionsMatch = ( dimensions , doBackAlias ) => {
825753 const target = doBackAlias ? backAlias ( dimsToMatch ) : dimsToMatch ;
@@ -1035,7 +963,7 @@ export class PreAggregations {
1035963 }
1036964
1037965 // TODO check multiplication factor didn't change
1038- private buildRollupJoin ( preAggObj : PreAggregationForQuery , preAggObjsToJoin : PreAggregationForQuery [ ] ) : RollupJoin {
966+ private buildRollupJoin ( preAggObj : PreAggregationForQuery , preAggObjsToJoin : PreAggregationForQuery [ ] ) : BuildRollupJoinResult {
1039967 return this . query . cacheValue (
1040968 [ 'buildRollupJoin' , JSON . stringify ( preAggObj ) , JSON . stringify ( preAggObjsToJoin ) ] ,
1041969 ( ) => {
@@ -1055,15 +983,22 @@ export class PreAggregations {
1055983
1056984 return hints ;
1057985 } ) . flat ( ) ;
1058- const targetJoins = this . resolveJoinMembers (
1059- this . query . joinGraph . buildJoin (
1060- preAggJoinsJoinHints . concat ( this . cubesFromPreAggregation ( preAggObj ) )
1061- )
986+
987+ const builtJoinTree = this . query . joinGraph . buildJoin (
988+ preAggJoinsJoinHints . concat ( this . cubesFromPreAggregation ( preAggObj ) )
1062989 ) ;
1063- const existingJoins = R . unnest ( preAggObjsToJoin . map (
1064- // TODO join hints?
1065- p => this . resolveJoinMembers ( this . query . joinGraph . buildJoin ( this . cubesFromPreAggregation ( p ) ) ! )
1066- ) ) ;
990+
991+ if ( ! builtJoinTree ) {
992+ throw new UserError ( `Can't build join tree for pre-aggregation ${ preAggObj . cube } .${ preAggObj . preAggregationName } ` ) ;
993+ }
994+
995+ const targetJoins = this . resolveJoinMembers ( builtJoinTree ) ;
996+
997+ // TODO join hints?
998+ const existingJoins = preAggObjsToJoin
999+ . map ( p => this . resolveJoinMembers ( this . query . joinGraph . buildJoin ( this . cubesFromPreAggregation ( p ) ) ! ) )
1000+ . flat ( ) ;
1001+
10671002 const nonExistingJoins = targetJoins . filter ( target => ! existingJoins . find (
10681003 existing => existing . originalFrom === target . originalFrom &&
10691004 existing . originalTo === target . originalTo &&
@@ -1073,7 +1008,7 @@ export class PreAggregations {
10731008 if ( ! nonExistingJoins . length ) {
10741009 throw new UserError ( `Nothing to join in rollup join. Target joins ${ JSON . stringify ( targetJoins ) } are included in existing rollup joins ${ JSON . stringify ( existingJoins ) } ` ) ;
10751010 }
1076- return nonExistingJoins . map ( join => {
1011+ const rollupJoin = nonExistingJoins . map ( join => {
10771012 const fromPreAggObj = this . preAggObjForJoin ( preAggObjsToJoin , join . fromMembers , join ) ;
10781013 const toPreAggObj = this . preAggObjForJoin ( preAggObjsToJoin , join . toMembers , join ) ;
10791014 return {
@@ -1082,6 +1017,11 @@ export class PreAggregations {
10821017 toPreAggObj
10831018 } ;
10841019 } ) ;
1020+
1021+ return {
1022+ rollupJoin,
1023+ existingJoins,
1024+ } ;
10851025 }
10861026 ) ;
10871027 }
@@ -1142,8 +1082,8 @@ export class PreAggregations {
11421082 preAggregationName,
11431083 preAggregation,
11441084 cube,
1145- // For rollupJoin and rollupLambda we need to pass references of the underlying rollups
1146- // to canUsePreAggregation fn, which are collected later;
1085+ // For rollupJoin and rollupLambda we need to enrich references with data
1086+ // from the underlying rollups which are collected later;
11471087 canUsePreAggregation : preAggregation . type === 'rollup' ? canUsePreAggregation ( references ) : false ,
11481088 references,
11491089 preAggregationId : `${ cube } .${ preAggregationName } `
@@ -1165,12 +1105,53 @@ export class PreAggregations {
11651105 preAggregationsToJoin . forEach ( preAgg => {
11661106 references . rollupsReferences . push ( preAgg . references ) ;
11671107 } ) ;
1168- const canUsePreAggregationResult = canUsePreAggregation ( references ) ;
1108+ const { rollupJoin, existingJoins } = this . buildRollupJoin ( preAggObj , preAggregationsToJoin ) ;
1109+
1110+ const joinsMap : Record < string , string > = { } ;
1111+ for ( const j of rollupJoin ) {
1112+ joinsMap [ j . to ] = j . from ;
1113+ }
1114+ for ( const j of existingJoins ) {
1115+ joinsMap [ j . to ] = j . from ;
1116+ }
1117+
1118+ const buildPath = ( cubeName : string ) : string [ ] => {
1119+ const path = [ cubeName ] ;
1120+ const parentMap = joinsMap ;
1121+ while ( parentMap [ cubeName ] ) {
1122+ cubeName = parentMap [ cubeName ] ;
1123+ path . push ( cubeName ) ;
1124+ }
1125+ return path . reverse ( ) ;
1126+ } ;
1127+
1128+ references . fullNameDimensions = references . dimensions . map ( d => {
1129+ const [ cubeName , ...restPath ] = d . split ( '.' ) ;
1130+ const path = buildPath ( cubeName ) ;
1131+
1132+ return `${ path . join ( '.' ) } .${ restPath . join ( '.' ) } ` ;
1133+ } ) ;
1134+ references . fullNameMeasures = references . measures . map ( m => {
1135+ const [ cubeName , ...restPath ] = m . split ( '.' ) ;
1136+ const path = buildPath ( cubeName ) ;
1137+
1138+ return `${ path . join ( '.' ) } .${ restPath . join ( '.' ) } ` ;
1139+ } ) ;
1140+ references . fullNameTimeDimensions = references . timeDimensions . map ( td => {
1141+ const [ cubeName , ...restPath ] = td . dimension . split ( '.' ) ;
1142+ const path = buildPath ( cubeName ) ;
1143+
1144+ return {
1145+ ...td ,
1146+ dimension : `${ path . join ( '.' ) } .${ restPath . join ( '.' ) } ` ,
1147+ } ;
1148+ } ) ;
1149+
11691150 return {
11701151 ...preAggObj ,
1171- canUsePreAggregation : canUsePreAggregationResult ,
1152+ canUsePreAggregation : canUsePreAggregation ( references ) ,
11721153 preAggregationsToJoin,
1173- rollupJoin : canUsePreAggregationResult ? this . buildRollupJoin ( preAggObj , preAggregationsToJoin ) : null ,
1154+ rollupJoin,
11741155 } ;
11751156 } else if ( preAggregation . type === 'rollupLambda' ) {
11761157 // TODO evaluation optimizations. Should be cached or moved to compile time.
@@ -1217,6 +1198,9 @@ export class PreAggregations {
12171198 } ) ;
12181199 referencedPreAggregations . forEach ( preAgg => {
12191200 references . rollupsReferences . push ( preAgg . references ) ;
1201+ references . fullNameDimensions . push ( ...preAgg . references . fullNameDimensions ) ;
1202+ references . fullNameMeasures . push ( ...preAgg . references . fullNameMeasures ) ;
1203+ references . fullNameTimeDimensions . push ( ...preAgg . references . fullNameTimeDimensions ) ;
12201204 } ) ;
12211205 return {
12221206 ...preAggObj ,
0 commit comments