@@ -282,7 +282,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
282282 const fieldRef = this . fieldRef (
283283 fieldDef . originModel ?? model ,
284284 key ,
285- fieldDef . originModel ?? modelAlias ,
285+ this . delegateFieldAlias ( model , modelAlias , fieldDef ) ,
286286 true ,
287287 computedArgs ,
288288 ) ;
@@ -328,10 +328,10 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
328328 const _order = negateOrderBy ? ( order === 'asc' ? 'desc' : 'asc' ) : order ;
329329 const op = j === i ? ( _order === 'asc' ? '>=' : '<=' ) : '=' ;
330330 // Fields inherited from a delegate base live on the base table, which is
331- // joined with its model name as alias . See buildSelectModel/buildDelegateJoin.
331+ // joined under `delegateJoinAlias` . See buildSelectModel/buildDelegateJoin.
332332 const fieldDef = requireField ( this . schema , model , field ) ;
333- const outerAlias = fieldDef . originModel ?? modelAlias ;
334- const subSelectAlias = fieldDef . originModel ?? subQueryAlias ;
333+ const outerAlias = this . delegateFieldAlias ( model , modelAlias , fieldDef ) ;
334+ const subSelectAlias = this . delegateFieldAlias ( model , subQueryAlias , fieldDef ) ;
335335 andFilters . push (
336336 this . eb (
337337 this . eb . ref ( `${ outerAlias } .${ field } ` ) ,
@@ -431,7 +431,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
431431 this . schema ,
432432 model ,
433433 // if field is from a base, use the base model to join
434- fieldDef . originModel ?? modelAlias ,
434+ this . delegateFieldAlias ( model , modelAlias , fieldDef ) ,
435435 field ,
436436 joinAlias ,
437437 ) ;
@@ -1184,7 +1184,13 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
11841184 const buildFieldRef = ( model : string , field : string , modelAlias : string , computedArgs ?: unknown ) => {
11851185 const fieldDef = requireField ( this . schema , model , field ) ;
11861186 return fieldDef . originModel
1187- ? this . fieldRef ( fieldDef . originModel , field , fieldDef . originModel , true , computedArgs )
1187+ ? this . fieldRef (
1188+ fieldDef . originModel ,
1189+ field ,
1190+ this . delegateJoinAlias ( model , modelAlias , fieldDef . originModel ) ,
1191+ true ,
1192+ computedArgs ,
1193+ )
11881194 : this . fieldRef ( model , field , modelAlias , true , computedArgs ) ;
11891195 } ;
11901196
@@ -1283,12 +1289,25 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
12831289
12841290 // order by to-one relation
12851291 const joinAlias = tmpAlias ( `${ modelAlias } $ob$${ index } ` ) ;
1286- const joined = query . leftJoin ( `${ relationModel } as ${ joinAlias } ` , ( join ) => {
1287- const joinPairs = buildJoinPairs ( this . schema , model , modelAlias , field , joinAlias ) ;
1292+ let joined = query . leftJoin ( `${ relationModel } as ${ joinAlias } ` , ( join ) => {
1293+ const joinPairs = buildJoinPairs (
1294+ this . schema ,
1295+ model ,
1296+ // if field is from a base, use the base model to join
1297+ this . delegateFieldAlias ( model , modelAlias , fieldDef ) ,
1298+ field ,
1299+ joinAlias ,
1300+ ) ;
12881301 return join . on ( ( eb ) =>
12891302 this . and ( ...joinPairs . map ( ( [ left , right ] ) => eb ( this . eb . ref ( left ) , '=' , this . eb . ref ( right ) ) ) ) ,
12901303 ) ;
12911304 } ) ;
1305+ // join delegate bases so that the ordering can reference inherited fields
1306+ let joinBase = requireModel ( this . schema , relationModel ) . baseModel ;
1307+ while ( joinBase ) {
1308+ joined = this . buildDelegateJoin ( relationModel , joinAlias , joinBase , joined ) ;
1309+ joinBase = requireModel ( this . schema , joinBase ) . baseModel ;
1310+ }
12921311 return this . buildOrderBy ( joined , relationModel , joinAlias , value , negated , take ) ;
12931312 }
12941313
@@ -1475,6 +1494,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
14751494 const descendants = getDelegateDescendantModels ( this . schema , model ) ;
14761495 for ( const subModel of descendants ) {
14771496 result = this . buildDelegateJoin ( model , modelAlias , subModel . name , result ) ;
1497+ const subModelAlias = this . delegateJoinAlias ( model , modelAlias , subModel . name ) ;
14781498 result = result . select ( ( ) => {
14791499 const jsonObject : Record < string , Expression < any > > = { } ;
14801500 for ( const fieldDef of getModelFields ( this . schema , subModel . name , { computed : true } ) ) {
@@ -1485,7 +1505,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
14851505 if ( fieldDef . computed && fieldDef . params ) {
14861506 continue ;
14871507 }
1488- jsonObject [ fieldDef . name ] = this . fieldRef ( subModel . name , fieldDef . name , subModel . name ) ;
1508+ jsonObject [ fieldDef . name ] = this . fieldRef ( subModel . name , fieldDef . name , subModelAlias ) ;
14891509 }
14901510 return this . buildJsonObject ( jsonObject ) . as ( `${ DELEGATE_JOINED_FIELD_PREFIX } ${ subModel . name } ` ) ;
14911511 } ) ;
@@ -1546,10 +1566,9 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
15461566 ) : SelectQueryBuilder < any , any , any > {
15471567 const fieldDef = requireField ( this . schema , model , field ) ;
15481568
1549- // if field is defined on a delegate base, the base model is joined with its
1550- // model name from outer query, so we should use it directly as the alias
1569+ // if field is defined on a delegate base, it's selected from the joined base table
15511570 const fieldModel = fieldDef . originModel ?? model ;
1552- const alias = fieldDef . originModel ?? modelAlias ;
1571+ const alias = this . delegateFieldAlias ( model , modelAlias , fieldDef ) ;
15531572
15541573 // `computedArgs` is set for a parameterized computed field selected via `select`/`include`
15551574 return query . select ( ( ) => this . fieldRef ( fieldModel , field , alias , true , computedArgs ) . as ( field ) ) ;
@@ -1558,11 +1577,13 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
15581577 buildDelegateJoin (
15591578 thisModel : string ,
15601579 thisModelAlias : string ,
1561- otherModelAlias : string ,
1580+ otherModel : string ,
15621581 query : SelectQueryBuilder < any , any , any > ,
15631582 ) {
15641583 const idFields = requireIdFields ( this . schema , thisModel ) ;
1565- query = query . leftJoin ( otherModelAlias , ( qb ) => {
1584+ const otherModelAlias = this . delegateJoinAlias ( thisModel , thisModelAlias , otherModel ) ;
1585+ const table = otherModelAlias === otherModel ? otherModel : `${ otherModel } as ${ otherModelAlias } ` ;
1586+ query = query . leftJoin ( table , ( qb ) => {
15661587 for ( const idField of idFields ) {
15671588 qb = qb . onRef ( `${ thisModelAlias } .${ idField } ` , '=' , `${ otherModelAlias } .${ idField } ` ) ;
15681589 }
@@ -1571,6 +1592,24 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
15711592 return query ;
15721593 }
15731594
1595+ /**
1596+ * Gets the alias under which a delegate base or sub model is joined to a model selected as `modelAlias`.
1597+ * A model selected under its own name (a top-level query) has them joined under their own model names.
1598+ * A model selected under another alias (a relation subquery) has them joined under aliases derived from
1599+ * it, so they never shadow a table of an enclosing query in the same delegate hierarchy.
1600+ */
1601+ delegateJoinAlias ( model : string , modelAlias : string , joinedModel : string ) {
1602+ return modelAlias === model ? joinedModel : tmpAlias ( `${ modelAlias } $${ joinedModel } ` ) ;
1603+ }
1604+
1605+ /**
1606+ * Gets the alias of the table holding a field of a model selected as `modelAlias`: the joined base
1607+ * table for a field inherited from a delegate base, otherwise the model's own table.
1608+ */
1609+ delegateFieldAlias ( model : string , modelAlias : string , fieldDef : FieldDef ) {
1610+ return fieldDef . originModel ? this . delegateJoinAlias ( model , modelAlias , fieldDef . originModel ) : modelAlias ;
1611+ }
1612+
15741613 buildCountJson ( model : string , eb : ExpressionBuilder < any , any > , parentAlias : string , payload : any ) {
15751614 const modelDef = requireModel ( this . schema , model ) ;
15761615 const toManyRelations = Object . entries ( modelDef . fields ) . filter ( ( [ , field ] ) => field . relation && field . array ) ;
0 commit comments