orm: move type logic to checker, so that sql queries can be used before type def

pull/5450/head
Alexander Medvednikov 2020-06-25 12:05:24 +02:00
parent a1bad50b2f
commit 786be1d1c3
5 changed files with 53 additions and 52 deletions

View File

@ -3,6 +3,7 @@
- coroutines - coroutines
- bring back lock{} - bring back lock{}
- thread safe arrays/maps
- C2V translator - C2V translator
- doom.v - doom.v
- rune type, replace ustring with []rune - rune type, replace ustring with []rune

View File

@ -11,14 +11,6 @@ struct Module {
//nr_downloads int //nr_downloads int
} }
struct User {
id int
age int
name string
is_customer bool
skipped_string string [skip]
}
fn test_orm_sqlite() { fn test_orm_sqlite() {
db := sqlite.connect(':memory:') or { panic(err) } db := sqlite.connect(':memory:') or { panic(err) }
db.exec("drop table if exists User") 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() { fn test_orm_pg() {
/* /*

View File

@ -822,6 +822,7 @@ pub:
table_name string table_name string
object_var_name string // `user` object_var_name string // `user`
table_type table.Type table_type table.Type
pos token.Position
} }
pub struct SqlExpr { pub struct SqlExpr {
@ -829,11 +830,14 @@ pub:
typ table.Type typ table.Type
is_count bool is_count bool
db_expr Expr // `db` in `sql db {` db_expr Expr // `db` in `sql db {`
table_name string
where_expr Expr where_expr Expr
has_where bool has_where bool
fields []table.Field
is_array bool is_array bool
table_type table.Type
pos token.Position
pub mut:
table_name string
fields []table.Field
} }
[inline] [inline]

View File

@ -1841,7 +1841,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.scope_returns = true c.scope_returns = true
} }
ast.SqlStmt { ast.SqlStmt {
c.sql_insert_expr(node) c.sql_stmt(node)
} }
ast.StructDecl { ast.StructDecl {
c.struct_decl(it) c.struct_decl(it)
@ -2680,7 +2680,34 @@ fn (c &Checker) fileis(s string) bool {
return c.file.path.contains(s) 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 { if node.has_where {
c.expr(node.where_expr) c.expr(node.where_expr)
} }
@ -2688,7 +2715,7 @@ fn (mut c Checker) sql_expr(node ast.SqlExpr) table.Type {
return node.typ 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) c.expr(node.db_expr)
return table.void_type return table.void_type
} }

View File

@ -8,17 +8,10 @@ import v.table
fn (mut p Parser) sql_expr() ast.Expr { fn (mut p Parser) sql_expr() ast.Expr {
// `sql db {` // `sql db {`
pos := p.tok.position()
p.check_name() p.check_name()
db_expr := p.expr(0) db_expr := p.expr(0)
p.check(.lcbr) 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) p.check(.key_select)
n := p.check_name() n := p.check_name()
is_count := n == 'count' is_count := n == 'count'
@ -28,8 +21,6 @@ fn (mut p Parser) sql_expr() ast.Expr {
typ = table.int_type typ = table.int_type
} }
table_type := p.parse_type() // `User` table_type := p.parse_type() // `User`
sym := p.table.get_type_symbol(table_type)
table_name := sym.name
mut where_expr := ast.Expr{} mut where_expr := ast.Expr{}
has_where := p.tok.kind == .name && p.tok.lit == 'where' has_where := p.tok.kind == .name && p.tok.lit == 'where'
mut query_one := false // one object is returned, not an array 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 typ = table_type
} }
p.check(.rcbr) 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{ return ast.SqlExpr{
is_count: is_count is_count: is_count
typ: typ typ: typ
db_expr: db_expr db_expr: db_expr
table_name: table_name //table_name: table_name
table_type: table_type
where_expr: where_expr where_expr: where_expr
has_where: has_where has_where: has_where
fields: fields //fields: fields
is_array: !query_one is_array: !query_one
pos: pos
} }
} }
// insert user into User // insert user into User
// update User set nr_oders=nr_orders+1 where id == user_id // update User set nr_oders=nr_orders+1 where id == user_id
fn (mut p Parser) sql_stmt() ast.SqlStmt { fn (mut p Parser) sql_stmt() ast.SqlStmt {
pos := p.tok.position()
p.inside_match = true p.inside_match = true
defer { defer {
p.inside_match = false p.inside_match = false
@ -172,6 +139,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
table_name: table_name table_name: table_name
table_type: table_type table_type: table_type
object_var_name: inserted_var_name object_var_name: inserted_var_name
pos: pos
} }
} }