@@ -363,6 +363,17 @@ export class BaseQuery {
363
363
try {
364
364
// TODO allJoinHints should contain join hints form pre-agg
365
365
this . join = this . joinGraph . buildJoin ( this . allJoinHints ) ;
366
+ /**
367
+ * @type {Record<string, string[]> }
368
+ */
369
+ const queryJoinGraph = { } ;
370
+ for ( const { originalFrom, originalTo } of ( this . join ?. joins || [ ] ) ) {
371
+ if ( ! queryJoinGraph [ originalFrom ] ) {
372
+ queryJoinGraph [ originalFrom ] = [ ] ;
373
+ }
374
+ queryJoinGraph [ originalFrom ] . push ( originalTo ) ;
375
+ }
376
+ this . joinGraphPaths = queryJoinGraph || { } ;
366
377
} catch ( e ) {
367
378
if ( this . useNativeSqlPlanner ) {
368
379
// Tesseract doesn't require join to be prebuilt and there's a case where single join can't be built for multi-fact query
@@ -4864,7 +4875,10 @@ export class BaseQuery {
4864
4875
*/
4865
4876
backAliasMembers ( members ) {
4866
4877
const query = this ;
4867
- return Object . fromEntries ( members . flatMap (
4878
+
4879
+ const buildJoinPath = this . buildJoinPathFn ( ) ;
4880
+
4881
+ const aliases = Object . fromEntries ( members . flatMap (
4868
4882
member => {
4869
4883
const collectedMembers = query . evaluateSymbolSqlWithContext (
4870
4884
( ) => query . collectFrom ( [ member ] , query . collectMemberNamesFor . bind ( query ) , 'collectMemberNamesFor' ) ,
@@ -4882,5 +4896,83 @@ export class BaseQuery {
4882
4896
. map ( d => [ query . cubeEvaluator . byPathAnyType ( d ) . aliasMember , memberPath ] ) ;
4883
4897
}
4884
4898
) ) ;
4899
+
4900
+ /**
4901
+ * @type {Record<string, string> }
4902
+ */
4903
+ const res = { } ;
4904
+ for ( const [ original , alias ] of Object . entries ( aliases ) ) {
4905
+ const [ cube , field ] = original . split ( '.' ) ;
4906
+ const path = buildJoinPath ( cube ) ;
4907
+
4908
+ const [ aliasCube , aliasField ] = alias . split ( '.' ) ;
4909
+ const aliasPath = aliasCube !== cube ? buildJoinPath ( aliasCube ) : path ;
4910
+
4911
+ if ( path ) {
4912
+ res [ `${ path } .${ field } ` ] = aliasPath ? `${ aliasPath } .${ aliasField } ` : alias ;
4913
+ }
4914
+
4915
+ // Aliases might come from proxied members, in such cases
4916
+ // we need to map them to originals too
4917
+ if ( aliasPath ) {
4918
+ res [ original ] = `${ aliasPath } .${ aliasField } ` ;
4919
+ }
4920
+ }
4921
+
4922
+ return res ;
4923
+ }
4924
+
4925
+ buildJoinPathFn ( ) {
4926
+ const query = this ;
4927
+ const { root } = this . join || { } ;
4928
+
4929
+ return ( target ) => {
4930
+ const visited = new Set ( ) ;
4931
+ const path = [ ] ;
4932
+
4933
+ /**
4934
+ * @param {string } node
4935
+ * @returns {boolean }
4936
+ */
4937
+ function dfs ( node ) {
4938
+ if ( node === target ) {
4939
+ path . push ( node ) ;
4940
+ return true ;
4941
+ }
4942
+
4943
+ if ( visited . has ( node ) ) return false ;
4944
+ visited . add ( node ) ;
4945
+
4946
+ const neighbors = query . joinGraphPaths [ node ] || [ ] ;
4947
+ for ( const neighbor of neighbors ) {
4948
+ if ( dfs ( neighbor ) ) {
4949
+ path . unshift ( node ) ;
4950
+ return true ;
4951
+ }
4952
+ }
4953
+
4954
+ return false ;
4955
+ }
4956
+
4957
+ return dfs ( root ) ? path . join ( '.' ) : null ;
4958
+ } ;
4959
+ }
4960
+
4961
+ resolveFullMemberPathFn ( ) {
4962
+ const { root : queryJoinRoot } = this . join || { } ;
4963
+
4964
+ const buildJoinPath = this . buildJoinPathFn ( ) ;
4965
+
4966
+ return ( member ) => {
4967
+ const [ cube , field ] = member . split ( '.' ) ;
4968
+ if ( ! cube || ! field ) return member ;
4969
+
4970
+ if ( cube === queryJoinRoot . root ) {
4971
+ return member ;
4972
+ }
4973
+
4974
+ const path = buildJoinPath ( cube ) ;
4975
+ return path ? `${ path } .${ field } ` : member ;
4976
+ } ;
4885
4977
}
4886
4978
}
0 commit comments