1 | pos token.Pos |
2 | where_expr Expr |
3 | update_exprs []Expr // for `update` |
4 | + // is_top_level indicates that a statement is parsed from code |
5 | + // and is not inserted by ORM for inserting in related tables. |
6 | + is_top_level bool |
7 | + scope &Scope = unsafe { nil } |
8 | pub mut: |
9 | object_var_name string // `user` |
10 | updated_columns []string // for `update set x=y` |
11 |
1 | info := sym.info as ast.Struct |
2 | mut fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, sym.name) |
3 | mut sub_structs := map[int]ast.SqlExpr{} |
4 | + |
5 | for f in fields.filter((c.table.type_symbols[int(it.typ)].kind == .struct_ |
6 | || (c.table.sym(it.typ).kind == .array |
7 | && c.table.sym(c.table.sym(it.typ).array_info().elem_type).kind == .struct_)) |
8 | tmp_inside_sql := c.inside_sql |
9 | c.sql_expr(mut n) |
10 | c.inside_sql = tmp_inside_sql |
11 | + |
12 | n.where_expr = ast.InfixExpr{ |
13 | op: .eq |
14 | pos: n.pos |
15 | |
16 | sub_structs[int(typ)] = n |
17 | } |
18 | + |
19 | if node.is_count { |
20 | fields = [ |
21 | ast.StructField{ |
22 | }, |
23 | ] |
24 | } |
25 | + |
26 | node.fields = fields |
27 | node.sub_structs = sub_structs.move() |
28 | + |
29 | if node.has_where { |
30 | c.expr(node.where_expr) |
31 | c.check_expr_has_no_fn_calls_with_non_orm_return_type(&node.where_expr) |
32 | defer { |
33 | c.cur_orm_ts = old_ts |
34 | } |
35 | + |
36 | + if node.kind == .insert && node.is_top_level { |
37 | + inserting_object_name := node.object_var_name |
38 | + inserting_object_var := node.scope.find(inserting_object_name) or { |
39 | + c.error('undefined ident: `${inserting_object_name}`', node.pos) |
40 | + return ast.void_type |
41 | + } |
42 | + |
43 | + if inserting_object_var.typ != node.table_expr.typ { |
44 | + table_name := table_sym.name |
45 | + inserting_type_name := c.table.sym(inserting_object_var.typ).name |
46 | + |
47 | + c.error('cannot use `${inserting_type_name}` as `${table_name}`', node.pos) |
48 | + return ast.void_type |
49 | + } |
50 | + } |
51 | + |
52 | if table_sym.info !is ast.Struct { |
53 | c.error('unknown type `${table_sym.name}`', node.pos) |
54 | return ast.void_type |
55 |
1 | new file mode 100644 |
2 | +vlib/v/checker/tests/orm_insert_object_with_mismatched_type_error.vv:19:10: error: cannot use `Tiddler` as `Tiddlers` |
3 | + 17 | sql db { |
4 | + 18 | create table Tiddlers |
5 | + 19 | insert tiddler into Tiddlers |
6 | + | ~~~~~~~ |
7 | + 20 | } |
8 | + 21 | } |
9 |
1 | new file mode 100644 |
2 | +import db.sqlite |
3 | +import json |
4 | + |
5 | +struct Tiddler { |
6 | + id int |
7 | + created int |
8 | +} |
9 | + |
10 | +struct Tiddlers { |
11 | + id int [primary; sql: serial] |
12 | + created string |
13 | +} |
14 | + |
15 | +fn main() { |
16 | + tiddler := json.decode(Tiddler, '{}') or { Tiddler{} } |
17 | + db := sqlite.connect(':memory:') or { panic(err) } |
18 | + sql db { |
19 | + create table Tiddlers |
20 | + insert tiddler into Tiddlers |
21 | + } |
22 | +} |
23 |
1 | new file mode 100644 |
2 | +vlib/v/checker/tests/orm_using_undefined_object_in_insert_error.vv:13:10: error: undefined ident: `bug` |
3 | + 11 | sql db { |
4 | + 12 | create table Node |
5 | + 13 | insert bug into Node |
6 | + | ~~~ |
7 | + 14 | } |
8 | + 15 | } |
9 |
1 | new file mode 100644 |
2 | +import db.sqlite |
3 | + |
4 | +struct Node { |
5 | + id int [primary; sql: serial] |
6 | + text string |
7 | +} |
8 | + |
9 | +fn main() { |
10 | + db := sqlite.connect(':memory:') or { panic(err) } |
11 | + |
12 | + sql db { |
13 | + create table Node |
14 | + insert bug into Node |
15 | + } |
16 | +} |
17 |
1 | typ: typ |
2 | pos: typ_pos |
3 | } |
4 | + scope: p.scope |
5 | } |
6 | } else if n == 'drop' { |
7 | kind = .drop |
8 | typ: typ |
9 | pos: typ_pos |
10 | } |
11 | + scope: p.scope |
12 | } |
13 | } |
14 | mut inserted_var_name := '' |
15 | update_exprs: update_exprs |
16 | kind: kind |
17 | where_expr: where_expr |
18 | + is_top_level: true |
19 | + scope: p.scope |
20 | } |
21 | } |
22 |