@@ -362,6 +362,17 @@ export class BaseQuery {
362
362
try {
363
363
// TODO allJoinHints should contain join hints form pre-agg
364
364
this . join = this . joinGraph . buildJoin ( this . allJoinHints ) ;
365
+ /**
366
+ * @type {Record<string, string[]> }
367
+ */
368
+ const queryJoinGraph = { } ;
369
+ for ( const { originalFrom, originalTo } of ( this . join ?. joins || [ ] ) ) {
370
+ if ( ! queryJoinGraph [ originalFrom ] ) {
371
+ queryJoinGraph [ originalFrom ] = [ ] ;
372
+ }
373
+ queryJoinGraph [ originalFrom ] . push ( originalTo ) ;
374
+ }
375
+ this . joinGraphPaths = queryJoinGraph || { } ;
365
376
} catch ( e ) {
366
377
if ( this . useNativeSqlPlanner ) {
367
378
// Tesseract doesn't require join to be prebuilt and there's a case where single join can't be built for multi-fact query
@@ -4677,7 +4688,10 @@ export class BaseQuery {
4677
4688
*/
4678
4689
backAliasMembers ( members ) {
4679
4690
const query = this ;
4680
- return Object . fromEntries ( members . flatMap (
4691
+
4692
+ const buildJoinPath = this . buildJoinPathFn ( ) ;
4693
+
4694
+ const aliases = Object . fromEntries ( members . flatMap (
4681
4695
member => {
4682
4696
const collectedMembers = query . evaluateSymbolSqlWithContext (
4683
4697
( ) => query . collectFrom ( [ member ] , query . collectMemberNamesFor . bind ( query ) , 'collectMemberNamesFor' ) ,
@@ -4695,5 +4709,83 @@ export class BaseQuery {
4695
4709
. map ( d => [ query . cubeEvaluator . byPathAnyType ( d ) . aliasMember , memberPath ] ) ;
4696
4710
}
4697
4711
) ) ;
4712
+
4713
+ /**
4714
+ * @type {Record<string, string> }
4715
+ */
4716
+ const res = { } ;
4717
+ for ( const [ original , alias ] of Object . entries ( aliases ) ) {
4718
+ const [ cube , field ] = original . split ( '.' ) ;
4719
+ const path = buildJoinPath ( cube ) ;
4720
+
4721
+ const [ aliasCube , aliasField ] = alias . split ( '.' ) ;
4722
+ const aliasPath = aliasCube !== cube ? buildJoinPath ( aliasCube ) : path ;
4723
+
4724
+ if ( path ) {
4725
+ res [ `${ path } .${ field } ` ] = aliasPath ? `${ aliasPath } .${ aliasField } ` : alias ;
4726
+ }
4727
+
4728
+ // Aliases might come from proxied members, in such cases
4729
+ // we need to map them to originals too
4730
+ if ( aliasPath ) {
4731
+ res [ original ] = `${ aliasPath } .${ aliasField } ` ;
4732
+ }
4733
+ }
4734
+
4735
+ return res ;
4736
+ }
4737
+
4738
+ buildJoinPathFn ( ) {
4739
+ const query = this ;
4740
+ const { root } = this . join || { } ;
4741
+
4742
+ return ( target ) => {
4743
+ const visited = new Set ( ) ;
4744
+ const path = [ ] ;
4745
+
4746
+ /**
4747
+ * @param {string } node
4748
+ * @returns {boolean }
4749
+ */
4750
+ function dfs ( node ) {
4751
+ if ( node === target ) {
4752
+ path . push ( node ) ;
4753
+ return true ;
4754
+ }
4755
+
4756
+ if ( visited . has ( node ) ) return false ;
4757
+ visited . add ( node ) ;
4758
+
4759
+ const neighbors = query . joinGraphPaths [ node ] || [ ] ;
4760
+ for ( const neighbor of neighbors ) {
4761
+ if ( dfs ( neighbor ) ) {
4762
+ path . unshift ( node ) ;
4763
+ return true ;
4764
+ }
4765
+ }
4766
+
4767
+ return false ;
4768
+ }
4769
+
4770
+ return dfs ( root ) ? path . join ( '.' ) : null ;
4771
+ } ;
4772
+ }
4773
+
4774
+ resolveFullMemberPathFn ( ) {
4775
+ const { root : queryJoinRoot } = this . join || { } ;
4776
+
4777
+ const buildJoinPath = this . buildJoinPathFn ( ) ;
4778
+
4779
+ return ( member ) => {
4780
+ const [ cube , field ] = member . split ( '.' ) ;
4781
+ if ( ! cube || ! field ) return member ;
4782
+
4783
+ if ( cube === queryJoinRoot . root ) {
4784
+ return member ;
4785
+ }
4786
+
4787
+ const path = buildJoinPath ( cube ) ;
4788
+ return path ? `${ path } .${ field } ` : member ;
4789
+ } ;
4698
4790
}
4699
4791
}
0 commit comments