@@ -265,7 +265,13 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
265265 } else if ( this . isNullNode ( left ) ) {
266266 return this . transformNullCheck ( right , expr . op ) ;
267267 } else {
268- return BinaryOperationNode . create ( left , this . transformOperator ( op ) , right ) ;
268+ const leftFieldDef = this . getFieldDefFromFieldRef ( normalizedLeft , context ) ;
269+ const rightFieldDef = this . getFieldDefFromFieldRef ( normalizedRight , context ) ;
270+ // Map ZModel operator to SQL operator string
271+ const sqlOp = op === '==' ? '=' : op ;
272+ return this . dialect
273+ . buildComparison ( new ExpressionWrapper ( left ) , leftFieldDef , sqlOp , new ExpressionWrapper ( right ) , rightFieldDef )
274+ . toOperationNode ( ) ;
269275 }
270276 }
271277
@@ -298,17 +304,17 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
298304 // if relation fields are used directly in comparison, it can only be compared with null,
299305 // so we normalize the args with the id field (use the first id field if multiple)
300306 let normalizedLeft : Expression = expr . left ;
301- if ( this . isRelationField ( expr . left , context . modelOrType ) ) {
307+ if ( this . isRelationField ( expr . left , context ) ) {
302308 invariant ( ExpressionUtils . isNull ( expr . right ) , 'only null comparison is supported for relation field' ) ;
303- const leftRelDef = this . getFieldDefFromFieldRef ( expr . left , context . modelOrType ) ;
309+ const leftRelDef = this . getFieldDefFromFieldRef ( expr . left , context ) ;
304310 invariant ( leftRelDef , 'failed to get relation field definition' ) ;
305311 const idFields = QueryUtils . requireIdFields ( this . schema , leftRelDef . type ) ;
306312 normalizedLeft = this . makeOrAppendMember ( normalizedLeft , idFields [ 0 ] ! ) ;
307313 }
308314 let normalizedRight : Expression = expr . right ;
309- if ( this . isRelationField ( expr . right , context . modelOrType ) ) {
315+ if ( this . isRelationField ( expr . right , context ) ) {
310316 invariant ( ExpressionUtils . isNull ( expr . left ) , 'only null comparison is supported for relation field' ) ;
311- const rightRelDef = this . getFieldDefFromFieldRef ( expr . right , context . modelOrType ) ;
317+ const rightRelDef = this . getFieldDefFromFieldRef ( expr . right , context ) ;
312318 invariant ( rightRelDef , 'failed to get relation field definition' ) ;
313319 const idFields = QueryUtils . requireIdFields ( this . schema , rightRelDef . type ) ;
314320 normalizedRight = this . makeOrAppendMember ( normalizedRight , idFields [ 0 ] ! ) ;
@@ -349,7 +355,7 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
349355 ) ;
350356
351357 let newContextModel : string ;
352- const fieldDef = this . getFieldDefFromFieldRef ( expr . left , context . modelOrType ) ;
358+ const fieldDef = this . getFieldDefFromFieldRef ( expr . left , context ) ;
353359 if ( fieldDef ) {
354360 invariant ( fieldDef . relation , `field is not a relation: ${ JSON . stringify ( expr . left ) } ` ) ;
355361 newContextModel = fieldDef . type ;
@@ -578,13 +584,6 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
578584 return logicalNot ( this . dialect , this . transform ( expr . operand , context ) ) ;
579585 }
580586
581- private transformOperator ( op : Exclude < BinaryOperator , '?' | '!' | '^' > ) {
582- const mappedOp = match ( op )
583- . with ( '==' , ( ) => '=' as const )
584- . otherwise ( ( ) => op ) ;
585- return OperatorNode . create ( mappedOp ) ;
586- }
587-
588587 @expr ( 'call' )
589588 // @ts -ignore
590589 private _call ( expr : CallExpression , context : ExpressionTransformerContext ) {
@@ -979,12 +978,18 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
979978 }
980979 }
981980
982- private isRelationField ( expr : Expression , model : string ) {
983- const fieldDef = this . getFieldDefFromFieldRef ( expr , model ) ;
981+ private isRelationField ( expr : Expression , context : ExpressionTransformerContext ) {
982+ const fieldDef = this . getFieldDefFromFieldRef ( expr , context ) ;
984983 return ! ! fieldDef ?. relation ;
985984 }
986985
987- private getFieldDefFromFieldRef ( expr : Expression , model : string ) : FieldDef | undefined {
986+ private getFieldDefFromFieldRef ( expr : Expression , context : ExpressionTransformerContext ) : FieldDef | undefined {
987+ // `this.foo` references belong to `thisType` (the outer model in collection-predicate
988+ // contexts); everything else uses `modelOrType`.
989+ const model =
990+ ExpressionUtils . isMember ( expr ) && ExpressionUtils . isThis ( expr . receiver )
991+ ? context . thisType
992+ : context . modelOrType ;
988993 if ( ExpressionUtils . isField ( expr ) ) {
989994 return QueryUtils . getField ( this . schema , model , expr . field ) ;
990995 } else if (
@@ -993,6 +998,19 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
993998 ExpressionUtils . isThis ( expr . receiver )
994999 ) {
9951000 return QueryUtils . getField ( this . schema , model , expr . members [ 0 ] ! ) ;
1001+ } else if ( ExpressionUtils . isMember ( expr ) && ExpressionUtils . isField ( expr . receiver ) ) {
1002+ // relation chain access (e.g. `owner.id`, `user.profile.uuid_field`): walk the
1003+ // relation hops and return the terminal field's FieldDef so native-type info
1004+ // (@db.*) is available for casting in buildComparison
1005+ const receiverDef = QueryUtils . getField ( this . schema , model , expr . receiver . field ) ;
1006+ if ( ! receiverDef ?. relation ) return undefined ;
1007+ let currModel = receiverDef . type ;
1008+ for ( let i = 0 ; i < expr . members . length - 1 ; i ++ ) {
1009+ const hopDef = QueryUtils . getField ( this . schema , currModel , expr . members [ i ] ! ) ;
1010+ if ( ! hopDef ?. relation ) return undefined ;
1011+ currModel = hopDef . type ;
1012+ }
1013+ return QueryUtils . getField ( this . schema , currModel , expr . members [ expr . members . length - 1 ] ! ) ;
9961014 } else {
9971015 return undefined ;
9981016 }
0 commit comments