@@ -441,12 +441,47 @@ export class BaseQuery {
441441 } ;
442442
443443 let prevJoins = this . join ;
444+ let prevJoinMembersJoinHints = joinMembersJoinHints ;
444445 let newJoin = this . joinGraph . buildJoin ( constructJH ( ) ) ;
445446
446- while ( newJoin ?. joins . length > 0 && ! R . equals ( prevJoins , newJoin ) ) {
447+ const isOrderPreserved = ( base , updated ) => {
448+ const common = base . filter ( value => updated . includes ( value ) ) ;
449+ const bFiltered = updated . filter ( value => common . includes ( value ) ) ;
450+
451+ return common . every ( ( x , i ) => x === bFiltered [ i ] ) ;
452+ } ;
453+
454+ const isJoinTreesEqual = ( a , b ) => {
455+ if ( ! a || ! b || a . root !== b . root || a . joins . length !== b . joins . length ) {
456+ return false ;
457+ }
458+
459+ // We don't care about the order of joins on the same level, so
460+ // we can compare them as sets.
461+ const aJoinsSet = new Set ( a . joins . map ( j => `${ j . originalFrom } ->${ j . originalTo } ` ) ) ;
462+ const bJoinsSet = new Set ( b . joins . map ( j => `${ j . originalFrom } ->${ j . originalTo } ` ) ) ;
463+
464+ if ( aJoinsSet . size !== bJoinsSet . size ) {
465+ return false ;
466+ }
467+
468+ for ( const val of aJoinsSet ) {
469+ if ( ! bJoinsSet . has ( val ) ) {
470+ return false ;
471+ }
472+ }
473+
474+ return true ;
475+ } ;
476+
477+ while ( newJoin ?. joins . length > 0 && ! isJoinTreesEqual ( prevJoins , newJoin ) ) {
447478 prevJoins = newJoin ;
448479 joinMembersJoinHints = this . collectJoinHintsFromMembers ( this . joinMembersFromJoin ( newJoin ) ) ;
480+ if ( ! isOrderPreserved ( prevJoinMembersJoinHints , joinMembersJoinHints ) ) {
481+ throw new UserError ( `Can not construct joins for the query, potential loop detected: ${ prevJoinMembersJoinHints . join ( '->' ) } vs ${ joinMembersJoinHints . join ( '->' ) } ` ) ;
482+ }
449483 newJoin = this . joinGraph . buildJoin ( constructJH ( ) ) ;
484+ prevJoinMembersJoinHints = joinMembersJoinHints ;
450485 }
451486
452487 this . collectedJoinHints = R . uniq ( constructJH ( ) ) ;
0 commit comments