alex

/

v Public
0 Issues 1 Contributor 0 Releases 4 Branches
Additions: 110 Deletions: 3 View patch
1 }
2 }
3
4+pub fn (t &TypeSymbol) has_field(name string) bool {
5+ t.find_field(name) or { return false }
6+
7+ return true
8+}
9+
10 fn (a &Aggregate) find_field(name string) ?StructField {
11 for mut field in unsafe { a.fields } {
12 if field.name == name {
13
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
1new file mode 100644
2+vlib/v/checker/tests/orm_left_side_expr_in_infix_expr_has_no_struct_field_error.vv:18:26: error: V ORM: left side of the `==` expression must be one of the `User`'s fields.
3+1 possibility: `id`.
4+ 16 |
5+ 17 | users := sql db {
6+ 18 | select from User where first == second
7+ | ~~~~~
8+ 19 | }
9+ 20 |
10
1new file mode 100644
2+import db.sqlite
3+
4+struct User {
5+ id int [primary; sql: serial]
6+}
7+
8+fn main() {
9+ mut db := sqlite.connect(':memory:') or { panic(err) }
10+
11+ sql db {
12+ create table User
13+ }
14+
15+ first := 'first'
16+ second := 'second'
17+
18+ users := sql db {
19+ select from User where first == second
20+ }
21+
22+ println(users)
23+}
24
1new file mode 100644
2+vlib/v/checker/tests/orm_wrong_where_expr_error.vv:15:26: error: V ORM: `where` expression must have at least one comparison for filtering rows
3+ 13 |
4+ 14 | users := sql db {
5+ 15 | select from User where 3
6+ | ^
7+ 16 | }
8+ 17 |
9
1new file mode 100644
2+import db.sqlite
3+
4+struct User {
5+ id int [primary; sql: serial]
6+}
7+
8+fn main() {
9+ mut db := sqlite.connect(':memory:') or { panic(err) }
10+
11+ sql db {
12+ create table User
13+ }
14+
15+ users := sql db {
16+ select from User where 3
17+ }
18+
19+ println(users)
20+}
21