diff --git a/0.3_roadmap.txt b/0.3_roadmap.txt index a2ba88827f..39e8b44406 100644 --- a/0.3_roadmap.txt +++ b/0.3_roadmap.txt @@ -3,6 +3,7 @@ - coroutines - bring back lock{} +- thread safe arrays/maps - C2V translator - doom.v - rune type, replace ustring with []rune diff --git a/vlib/orm/orm_test.v b/vlib/orm/orm_test.v index 7c5eb0f7d3..b2de07953f 100644 --- a/vlib/orm/orm_test.v +++ b/vlib/orm/orm_test.v @@ -11,14 +11,6 @@ struct Module { //nr_downloads int } -struct User { - id int - age int - name string - is_customer bool - skipped_string string [skip] -} - fn test_orm_sqlite() { db := sqlite.connect(':memory:') or { panic(err) } db.exec("drop table if exists User") @@ -131,6 +123,15 @@ fn test_orm_sqlite() { */ } +struct User { + id int + age int + name string + is_customer bool + skipped_string string [skip] +} + + fn test_orm_pg() { /* diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 23de277e02..ebb3b69dd3 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -822,6 +822,7 @@ pub: table_name string object_var_name string // `user` table_type table.Type + pos token.Position } pub struct SqlExpr { @@ -829,11 +830,14 @@ pub: typ table.Type is_count bool db_expr Expr // `db` in `sql db {` - table_name string where_expr Expr has_where bool - fields []table.Field is_array bool + table_type table.Type + pos token.Position +pub mut: + table_name string + fields []table.Field } [inline] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index cd0bb9ef38..8630acccfe 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1841,7 +1841,7 @@ fn (mut c Checker) stmt(node ast.Stmt) { c.scope_returns = true } ast.SqlStmt { - c.sql_insert_expr(node) + c.sql_stmt(node) } ast.StructDecl { c.struct_decl(it) @@ -2680,7 +2680,34 @@ fn (c &Checker) fileis(s string) bool { return c.file.path.contains(s) } -fn (mut c Checker) sql_expr(node ast.SqlExpr) table.Type { +fn (mut c Checker) sql_expr(mut node ast.SqlExpr) table.Type { + sym := c.table.get_type_symbol(node.table_type) + info := sym.info as table.Struct + fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type] && + 'skip' !in it.attrs) + if fields.len == 0 { + c.error('V orm: select: empty fields in `$node.table_name`', node.pos) + } + if fields[0].name != 'id' { + c.error('V orm: `id int` must be the first field in `$node.table_name`', node.pos) + } + node.fields = fields + node.table_name = sym.name + if node.has_where { + // Register this type's fields as variables so they can be used in `where` + // expressions + scope := c.file.scope.innermost(node.pos.pos) + for field in fields { + // println('registering sql field var $field.name') + scope.register(field.name, ast.Var{ + name: field.name + typ: field.typ + is_mut: true + is_used: true + is_changed: true + }) + } + } if node.has_where { c.expr(node.where_expr) } @@ -2688,7 +2715,7 @@ fn (mut c Checker) sql_expr(node ast.SqlExpr) table.Type { return node.typ } -fn (mut c Checker) sql_insert_expr(node ast.SqlStmt) table.Type { +fn (mut c Checker) sql_stmt(node ast.SqlStmt) table.Type { c.expr(node.db_expr) return table.void_type } diff --git a/vlib/v/parser/sql.v b/vlib/v/parser/sql.v index 8263275bd8..f901a5c5a4 100644 --- a/vlib/v/parser/sql.v +++ b/vlib/v/parser/sql.v @@ -8,17 +8,10 @@ import v.table fn (mut p Parser) sql_expr() ast.Expr { // `sql db {` + pos := p.tok.position() p.check_name() db_expr := p.expr(0) p.check(.lcbr) - // kind := ast.SqlExprKind.select_ - // - /* - if p.tok.kind == .name && p.tok.lit == 'insert' { - return p.sql_insert_expr(db_var_name) - // kind = .insert - } - */ p.check(.key_select) n := p.check_name() is_count := n == 'count' @@ -28,8 +21,6 @@ fn (mut p Parser) sql_expr() ast.Expr { typ = table.int_type } table_type := p.parse_type() // `User` - sym := p.table.get_type_symbol(table_type) - table_name := sym.name mut where_expr := ast.Expr{} has_where := p.tok.kind == .name && p.tok.lit == 'where' mut query_one := false // one object is returned, not an array @@ -65,48 +56,24 @@ fn (mut p Parser) sql_expr() ast.Expr { typ = table_type } p.check(.rcbr) - // ///////// - // Register this type's fields as variables so they can be used in `where` - // expressions - // fields := typ.fields.filter(typ == 'string' || typ == 'int') - // fields := typ.fields - // get only string and int fields - // mut fields := []Var - info := sym.info as table.Struct - fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type] && - 'skip' !in it.attrs) - if fields.len == 0 { - p.error('V orm: select: empty fields in `$table_name`') - } - if fields[0].name != 'id' { - p.error('V orm: `id int` must be the first field in `$table_name`') - } - for field in fields { - // println('registering sql field var $field.name') - p.scope.register(field.name, ast.Var{ - name: field.name - typ: field.typ - is_mut: true - is_used: true - is_changed: true - }) - } - // //////////// return ast.SqlExpr{ is_count: is_count typ: typ db_expr: db_expr - table_name: table_name + //table_name: table_name + table_type: table_type where_expr: where_expr has_where: has_where - fields: fields + //fields: fields is_array: !query_one + pos: pos } } // insert user into User // update User set nr_oders=nr_orders+1 where id == user_id fn (mut p Parser) sql_stmt() ast.SqlStmt { + pos := p.tok.position() p.inside_match = true defer { p.inside_match = false @@ -172,6 +139,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt { table_name: table_name table_type: table_type object_var_name: inserted_var_name + pos: pos } }