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
- bring back lock{}
- thread safe arrays/maps
- C2V translator
- doom.v
- rune type, replace ustring with []rune

View File

@ -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() {
/*

View File

@ -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]

View File

@ -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
}

View File

@ -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
}
}