@@ -386,6 +386,53 @@ export class BaseQuery {
386386 }
387387 }
388388
389+ /**
390+ * Is used by native
391+ * This function follows the same logic as in this.collectJoinHints()
392+ * @private
393+ * @param {Array<(Array<string> | string)> } hints
394+ * @return {import('../compiler/JoinGraph').FinishedJoinTree }
395+ */
396+ joinTreeForHints ( hints ) {
397+ const explicitJoinHintMembers = new Set ( hints . filter ( j => Array . isArray ( j ) ) . flat ( ) ) ;
398+ const queryJoinMaps = this . queryJoinMap ( ) ;
399+ const newCollectedHints = [ ] ;
400+
401+ const constructJH = ( ) => R . uniq ( this . enrichHintsWithJoinMap ( [
402+ ...newCollectedHints ,
403+ ...hints ,
404+ ] ,
405+ queryJoinMaps ) ) ;
406+
407+ let prevJoin = null ;
408+ let newJoin = null ;
409+
410+ // Safeguard against infinite loop in case of cyclic joins somehow managed to slip through
411+ let cnt = 0 ;
412+ let newJoinHintsCollectedCnt ;
413+
414+ do {
415+ const allJoinHints = constructJH ( ) ;
416+ prevJoin = newJoin ;
417+ newJoin = this . joinGraph . buildJoin ( allJoinHints ) ;
418+ const allJoinHintsFlatten = new Set ( allJoinHints . flat ( ) ) ;
419+ const joinMembersJoinHints = this . collectJoinHintsFromMembers ( this . joinMembersFromJoin ( newJoin ) ) ;
420+
421+ const iterationCollectedHints = joinMembersJoinHints . filter ( j => ! allJoinHintsFlatten . has ( j ) ) ;
422+ newJoinHintsCollectedCnt = iterationCollectedHints . length ;
423+ cnt ++ ;
424+ if ( newJoin ) {
425+ newCollectedHints . push ( ...joinMembersJoinHints . filter ( j => ! explicitJoinHintMembers . has ( j ) ) ) ;
426+ }
427+ } while ( newJoin ?. joins . length > 0 && ! this . isJoinTreesEqual ( prevJoin , newJoin ) && cnt < 10000 && newJoinHintsCollectedCnt > 0 ) ;
428+
429+ if ( cnt >= 10000 ) {
430+ throw new UserError ( 'Can not construct joins for the query, potential loop detected' ) ;
431+ }
432+
433+ return newJoin ;
434+ }
435+
389436 cacheValue ( key , fn , { contextPropNames, inputProps, cache } = { } ) {
390437 const currentContext = this . safeEvaluateSymbolContext ( ) ;
391438 if ( contextPropNames ) {
@@ -450,7 +497,7 @@ export class BaseQuery {
450497
451498 for ( const member of queryMembers ) {
452499 const memberCube = member . cube ?. ( ) ;
453- if ( memberCube ?. isView && ! joinMaps [ memberCube . name ] ) {
500+ if ( memberCube ?. isView && ! joinMaps [ memberCube . name ] && memberCube . joinMap ) {
454501 joinMaps [ memberCube . name ] = memberCube . joinMap ;
455502 }
456503 }
0 commit comments