1 | } else { |
2 | ast.Type(0) |
3 | } |
4 | + |
5 | mut n := ast.SqlExpr{ |
6 | pos: node.pos |
7 | has_where: true |
8 | + where_expr: ast.None{} |
9 | typ: typ |
10 | db_expr: node.db_expr |
11 | table_expr: ast.TypeNode{ |
12 | typ: typ |
13 | } |
14 | } |
15 | + |
16 | tmp_inside_sql := c.inside_sql |
17 | c.sql_expr(mut n) |
18 | c.inside_sql = tmp_inside_sql |
19 | |
20 | node.fields = fields |
21 | node.sub_structs = sub_structs.move() |
22 | + field_names := fields.map(it.name) |
23 | |
24 | if node.has_where { |
25 | c.expr(node.where_expr) |
26 | c.check_expr_has_no_fn_calls_with_non_orm_return_type(&node.where_expr) |
27 | + c.check_where_expr_has_no_pointless_exprs(sym, field_names, &node.where_expr) |
28 | } |
29 | |
30 | if node.has_order { |
31 | if mut node.order_expr is ast.Ident { |
32 | order_ident_name := node.order_expr.name |
33 | |
34 | - sym.find_field(order_ident_name) or { |
35 | - field_names := fields.map(it.name) |
36 | - |
37 | + if !sym.has_field(order_ident_name) { |
38 | c.orm_error(util.new_suggestion(order_ident_name, field_names).say('`${sym.name}` structure has no field with name `${order_ident_name}`'), |
39 | node.order_expr.pos) |
40 | return ast.void_type |
41 | } |
42 | } |
43 | |
44 | +// check_where_expr_has_no_pointless_exprs checks that an expression has no pointless expressions |
45 | +// which don't affect the result. For example, `where 3` is pointless. |
46 | +// Also, it checks that the left side of the infix expression is always the structure field. |
47 | +fn (mut c Checker) check_where_expr_has_no_pointless_exprs(table_type_symbol &ast.TypeSymbol, field_names []string, expr &ast.Expr) { |
48 | + // Skip type checking for generated subqueries |
49 | + // that are not linked to scope and vars but only created for cgen. |
50 | + if expr is ast.None { |
51 | + return |
52 | + } |
53 | + |
54 | + if expr is ast.InfixExpr { |
55 | + has_no_field_error := "left side of the `${expr.op}` expression must be one of the `${table_type_symbol.name}`'s fields" |
56 | + |
57 | + if expr.left is ast.Ident { |
58 | + left_ident_name := expr.left.name |
59 | + |
60 | + if !table_type_symbol.has_field(left_ident_name) { |
61 | + c.orm_error(util.new_suggestion(left_ident_name, field_names).say(has_no_field_error), |
62 | + expr.left.pos) |
63 | + } |
64 | + } else if expr.left is ast.InfixExpr || expr.left is ast.ParExpr |
65 | + || expr.left is ast.PrefixExpr { |
66 | + c.check_where_expr_has_no_pointless_exprs(table_type_symbol, field_names, |
67 | + &expr.left) |
68 | + } else { |
69 | + c.orm_error(has_no_field_error, expr.left.pos()) |
70 | + } |
71 | + |
72 | + if expr.right is ast.InfixExpr || expr.right is ast.ParExpr || expr.right is ast.PrefixExpr { |
73 | + c.check_where_expr_has_no_pointless_exprs(table_type_symbol, field_names, |
74 | + &expr.right) |
75 | + } |
76 | + } else if expr is ast.ParExpr { |
77 | + c.check_where_expr_has_no_pointless_exprs(table_type_symbol, field_names, &expr.expr) |
78 | + } else if expr is ast.PrefixExpr { |
79 | + c.check_where_expr_has_no_pointless_exprs(table_type_symbol, field_names, &expr.right) |
80 | + } else { |
81 | + c.orm_error('`where` expression must have at least one comparison for filtering rows', |
82 | + expr.pos()) |
83 | + } |
84 | +} |
85 | + |
86 | fn (_ &Checker) fn_return_type_flag_to_string(typ ast.Type) string { |
87 | is_result_type := typ.has_flag(.result) |
88 | is_option_type := typ.has_flag(.option) |
89 | |