orm: insert

pull/5426/head
Alexander Medvednikov 2020-06-19 16:43:32 +02:00
parent c78cfa43bc
commit cd8392e42d
9 changed files with 137 additions and 17 deletions

View File

@ -80,12 +80,20 @@ fn test_orm_sqlite() {
assert users3.len == 2 assert users3.len == 2
assert users3[0].age == 29 assert users3[0].age == 29
assert users3[1].age == 31 assert users3[1].age == 31
//
//user2 := User{} new_user := User{name:'New user' age:30}
//x := sql db { sql db {
//insert user2 into User insert new_user into User
//} }
//db.insert<User>(user2) //db.insert<User>(user2)
x := sql db {
select from User where id == 4
}
println(x)
assert x.age == 30
assert x.id == 4
assert x.name == 'New user'
} }

View File

@ -17,8 +17,8 @@ pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | C
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl |
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | TypeDecl | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | SqlInsertExpr |
UnsafeStmt StructDecl | TypeDecl | UnsafeStmt
pub type ScopeObject = ConstField | GlobalDecl | Var pub type ScopeObject = ConstField | GlobalDecl | Var
@ -808,6 +808,21 @@ pub:
foo int // todo foo int // todo
} }
/*
pub enum SqlExprKind {
select_
insert
update
}
*/
pub struct SqlInsertExpr {
pub:
db_var_name string // `db` in `sql db {`
table_name string
fields []table.Field
object_var_name string // `user`
}
pub struct SqlExpr { pub struct SqlExpr {
pub: pub:
typ table.Type typ table.Type
@ -820,9 +835,6 @@ pub:
is_array bool is_array bool
} }
pub struct SqlInsertExpr {
}
[inline] [inline]
pub fn (expr Expr) is_blank_ident() bool { pub fn (expr Expr) is_blank_ident() bool {
match expr { match expr {

View File

@ -2011,6 +2011,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
ast.SqlExpr { ast.SqlExpr {
return c.sql_expr(node) return c.sql_expr(node)
} }
ast.SqlInsertExpr {
return c.sql_insert_expr(node)
}
ast.StringLiteral { ast.StringLiteral {
if node.language == .c { if node.language == .c {
return table.byteptr_type return table.byteptr_type
@ -2608,6 +2611,10 @@ 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.SqlInsertExpr) table.Type {
return table.void_type
}
fn (mut c Checker) fn_decl(it ast.FnDecl) { fn (mut c Checker) fn_decl(it ast.FnDecl) {
if it.is_generic && c.cur_generic_type == 0 { // need the cur_generic_type check to avoid inf. recursion if it.is_generic && c.cur_generic_type == 0 { // need the cur_generic_type check to avoid inf. recursion
// loop thru each generic type and generate a function // loop thru each generic type and generate a function

View File

@ -360,6 +360,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
} }
f.writeln('') f.writeln('')
} }
ast.SqlInsertExpr {}
ast.StructDecl { ast.StructDecl {
f.struct_decl(it) f.struct_decl(it)
} }
@ -714,6 +715,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.write(')') f.write(')')
} }
ast.SqlExpr {} ast.SqlExpr {}
ast.SqlInsertExpr {}
ast.StringLiteral { ast.StringLiteral {
if node.is_raw { if node.is_raw {
f.write('r') f.write('r')

View File

@ -622,6 +622,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.const_decl(node) g.const_decl(node)
// } // }
} }
ast.Comment {}
ast.CompIf { ast.CompIf {
g.comp_if(node) g.comp_if(node)
} }
@ -660,6 +661,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
} }
} }
ast.FnDecl { ast.FnDecl {
g.tmp_count = 0
mut skip := false mut skip := false
pos := g.out.buf.len pos := g.out.buf.len
if g.pref.build_mode == .build_module { if g.pref.build_mode == .build_module {
@ -767,6 +769,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.write_autofree_stmts_when_needed(node) g.write_autofree_stmts_when_needed(node)
g.return_statement(node) g.return_statement(node)
} }
ast.SqlInsertExpr{
g.sql_insert_expr(node)
}
ast.StructDecl { ast.StructDecl {
name := if node.language == .c { node.name.replace('.', '__') } else { c_name(node.name) } name := if node.language == .c { node.name.replace('.', '__') } else { c_name(node.name) }
// g.writeln('typedef struct {') // g.writeln('typedef struct {')
@ -790,9 +795,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.UnsafeStmt { ast.UnsafeStmt {
g.stmts(node.stmts) g.stmts(node.stmts)
} }
else {
verror('cgen.stmt(): unhandled node ' + typeof(node))
}
} }
g.stmt_path_pos.delete(g.stmt_path_pos.len - 1) g.stmt_path_pos.delete(g.stmt_path_pos.len - 1)
} }
@ -1585,6 +1587,9 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.SqlExpr { ast.SqlExpr {
g.sql_select_expr(node) g.sql_select_expr(node)
} }
//ast.SqlInsertExpr {
//g.sql_insert_expr(node)
//}
ast.StringLiteral { ast.StringLiteral {
if node.is_raw { if node.is_raw {
escaped_val := node.val.replace_each(['"', '\\"', '\\', '\\\\']) escaped_val := node.val.replace_each(['"', '\\"', '\\', '\\\\'])

View File

@ -501,6 +501,8 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
} }
g.gen_return_stmt(it) g.gen_return_stmt(it)
} }
ast.SqlInsertExpr{
}
ast.StructDecl { ast.StructDecl {
g.gen_struct_decl(it) g.gen_struct_decl(it)
} }
@ -608,6 +610,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
ast.SqlExpr{ ast.SqlExpr{
// TODO // TODO
} }
ast.SqlInsertExpr{
// TODO
}
ast.StringInterLiteral { ast.StringInterLiteral {
g.gen_string_inter_literal(it) g.gen_string_inter_literal(it)
} }

View File

@ -13,6 +13,45 @@ const (
) )
fn (mut g Gen) sql_insert_expr(node ast.SqlInsertExpr) { fn (mut g Gen) sql_insert_expr(node ast.SqlInsertExpr) {
g.writeln('\n\t// sql insert')
db_name := g.new_tmp_var()
g.sql_stmt_name = g.new_tmp_var()
g.writeln('${dbtype}__DB $db_name = $node.db_var_name;')
mut q := 'insert into $node.table_name ('
for i, field in node.fields {
if field.name == 'id' {
continue
}
q += '$field.name'
if i < node.fields.len - 1 {
q += ', '
}
}
q += ') values ('
for i, field in node.fields {
if field.name == 'id' {
continue
}
q += '?${i+0}'
if i < node.fields.len - 1 {
q += ', '
}
}
q += ')'
g.writeln('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q"));')
for i, field in node.fields {
if field.name == 'id' {
continue
}
x := '${node.object_var_name}.$field.name'
if field.typ == table.string_type {
g.writeln('sqlite3_bind_text($g.sql_stmt_name, ${i+0}, ${x}.str, ${x}.len, 0);')
} else {
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i+0}, $x); //insertl')
}
}
g.writeln('sqlite3_step($g.sql_stmt_name);')
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
} }
fn (mut g Gen) sql_select_expr(node ast.SqlExpr) { fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
@ -48,9 +87,9 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
// g.write('${dbtype}__DB_q_int(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q') // g.write('${dbtype}__DB_q_int(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q')
g.sql_stmt_name = g.new_tmp_var() g.sql_stmt_name = g.new_tmp_var()
db_name := g.new_tmp_var() db_name := g.new_tmp_var()
g.writeln('\n\t// sql') g.writeln('\n\t// sql select')
// g.write('${dbtype}__DB $db_name = *(${dbtype}__DB*)${node.db_var_name}.data;') // g.write('${dbtype}__DB $db_name = *(${dbtype}__DB*)${node.db_var_name}.data;')
g.writeln('${dbtype}__DB $db_name = ${node.db_var_name};') g.writeln('${dbtype}__DB $db_name = $node.db_var_name;')
// g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q') // g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q')
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q') g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q')
if node.has_where && node.where_expr is ast.InfixExpr { if node.has_where && node.where_expr is ast.InfixExpr {
@ -118,8 +157,8 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
// not a V variable. Need to distinguish column names from V variables. // not a V variable. Need to distinguish column names from V variables.
match expr { match expr {
ast.InfixExpr { ast.InfixExpr {
g.expr_to_sql(it.left) g.expr_to_sql(expr.left)
match it.op { match expr.op {
.eq { g.write(' = ') } .eq { g.write(' = ') }
.gt { g.write(' > ') } .gt { g.write(' > ') }
.lt { g.write(' < ') } .lt { g.write(' < ') }

View File

@ -518,6 +518,9 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
} }
.name, .key_mut, .key_static, .mul { .name, .key_mut, .key_static, .mul {
if p.tok.kind == .name { if p.tok.kind == .name {
if p.tok.lit == 'sql' {
return p.sql_insert_expr()
}
if p.peek_tok.kind == .colon { if p.peek_tok.kind == .colon {
// `label:` // `label:`
name := p.check_name() name := p.check_name()

View File

@ -6,12 +6,19 @@ module parser
import v.ast import v.ast
import v.table import v.table
fn (mut p Parser) sql_expr() ast.SqlExpr { fn (mut p Parser) sql_expr() ast.Expr {
// `sql db {` // `sql db {`
p.check_name() p.check_name()
db_var_name := p.check_name() db_var_name := p.check_name()
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'
@ -97,3 +104,35 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
is_array: !query_one is_array: !query_one
} }
} }
fn (mut p Parser) sql_insert_expr() ast.SqlInsertExpr {
// `sql db {`
p.check_name()
db_var_name := p.check_name()
p.check(.lcbr)
// kind := ast.SqlExprKind.select_
//
p.check_name() // insert
mut object_var_name := ''
expr := p.expr(0)
match expr {
ast.Ident { object_var_name = expr.name }
else { p.error('can only insert variables') }
}
n := p.check_name() // into
if n != 'into' {
p.error('expecting `into`')
}
table_type := p.parse_type() // `User`
sym := p.table.get_type_symbol(table_type)
info := sym.info as table.Struct
fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type])
table_name := sym.name
p.check(.rcbr)
return ast.SqlInsertExpr{
db_var_name: db_var_name
table_name: table_name
fields: fields
object_var_name: object_var_name
}
}