@@ -42,16 +42,19 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
42
42
} else {
43
43
ast.Type (0 )
44
44
}
45
+
45
46
mut n := ast.SqlExpr{
46
47
pos: node.pos
47
48
has_where: true
49
+ where_expr: ast.None{}
48
50
typ: typ
49
51
db_expr: node.db_expr
50
52
table_expr: ast.TypeNode{
51
53
pos: node.table_expr.pos
52
54
typ: typ
53
55
}
54
56
}
57
+
55
58
tmp_inside_sql := c.inside_sql
56
59
c.sql_expr (mut n)
57
60
c.inside_sql = tmp_inside_sql
@@ -100,19 +103,19 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type {
100
103
101
104
node.fields = fields
102
105
node.sub_structs = sub_structs.move ()
106
+ field_names := fields.map (it .name)
103
107
104
108
if node.has_where {
105
109
c.expr (node.where_expr)
106
110
c.check_expr_has_no_fn_calls_with_non_orm_return_type (& node.where_expr)
111
+ c.check_where_expr_has_no_pointless_exprs (sym, field_names, & node.where_expr)
107
112
}
108
113
109
114
if node.has_order {
110
115
if mut node.order_expr is ast.Ident {
111
116
order_ident_name := node.order_expr.name
112
117
113
- sym.find_field (order_ident_name) or {
114
- field_names := fields.map (it .name)
115
-
118
+ if ! sym.has_field (order_ident_name) {
116
119
c.orm_error (util.new_suggestion (order_ident_name, field_names).say ('`${sym.name} ` structure has no field with name `${order_ident_name} `' ),
117
120
node.order_expr.pos)
118
121
return ast.void_type
@@ -402,6 +405,48 @@ fn (mut c Checker) check_expr_has_no_fn_calls_with_non_orm_return_type(expr &ast
402
405
}
403
406
}
404
407
408
+ // check_where_expr_has_no_pointless_exprs checks that an expression has no pointless expressions
409
+ // which don't affect the result. For example, `where 3` is pointless.
410
+ // Also, it checks that the left side of the infix expression is always the structure field.
411
+ fn (mut c Checker) check_where_expr_has_no_pointless_exprs (table_type_symbol & ast.TypeSymbol, field_names []string , expr & ast.Expr) {
412
+ // Skip type checking for generated subqueries
413
+ // that are not linked to scope and vars but only created for cgen.
414
+ if expr is ast.None {
415
+ return
416
+ }
417
+
418
+ if expr is ast.InfixExpr {
419
+ has_no_field_error := "left side of the `${expr.op} ` expression must be one of the `${table_type_symbol.name} `'s fields"
420
+
421
+ if expr.left is ast.Ident {
422
+ left_ident_name := expr.left.name
423
+
424
+ if ! table_type_symbol.has_field (left_ident_name) {
425
+ c.orm_error (util.new_suggestion (left_ident_name, field_names).say (has_no_field_error),
426
+ expr.left.pos)
427
+ }
428
+ } else if expr.left is ast.InfixExpr || expr.left is ast.ParExpr
429
+ || expr.left is ast.PrefixExpr {
430
+ c.check_where_expr_has_no_pointless_exprs (table_type_symbol, field_names,
431
+ & expr.left)
432
+ } else {
433
+ c.orm_error (has_no_field_error, expr.left.pos ())
434
+ }
435
+
436
+ if expr.right is ast.InfixExpr || expr.right is ast.ParExpr || expr.right is ast.PrefixExpr {
437
+ c.check_where_expr_has_no_pointless_exprs (table_type_symbol, field_names,
438
+ & expr.right)
439
+ }
440
+ } else if expr is ast.ParExpr {
441
+ c.check_where_expr_has_no_pointless_exprs (table_type_symbol, field_names, & expr.expr)
442
+ } else if expr is ast.PrefixExpr {
443
+ c.check_where_expr_has_no_pointless_exprs (table_type_symbol, field_names, & expr.right)
444
+ } else {
445
+ c.orm_error ('`where` expression must have at least one comparison for filtering rows' ,
446
+ expr.pos ())
447
+ }
448
+ }
449
+
405
450
fn (_ &Checker) fn_return_type_flag_to_string (typ ast.Type) string {
406
451
is_result_type := typ.has_flag (.result)
407
452
is_option_type := typ.has_flag (.option)
0 commit comments