orm: `update` cgen
parent
a8b0dfb38a
commit
b280e08ee0
|
@ -116,11 +116,15 @@ fn test_orm_sqlite() {
|
||||||
assert customer.is_customer == true
|
assert customer.is_customer == true
|
||||||
assert customer.name == 'Kate'
|
assert customer.name == 'Kate'
|
||||||
//
|
//
|
||||||
/*
|
|
||||||
sql db {
|
sql db {
|
||||||
update User set age = 31 where name == 'Kate'
|
update User set age = 31 where name == 'Kate'
|
||||||
}
|
}
|
||||||
*/
|
kate2 := sql db {
|
||||||
|
select from User where id == 3
|
||||||
|
}
|
||||||
|
println(kate2)
|
||||||
|
assert kate2.age == 31
|
||||||
|
assert kate2.name == 'Kate'
|
||||||
}
|
}
|
||||||
|
|
||||||
struct User {
|
struct User {
|
||||||
|
|
|
@ -822,6 +822,9 @@ pub:
|
||||||
object_var_name string // `user`
|
object_var_name string // `user`
|
||||||
table_type table.Type
|
table_type table.Type
|
||||||
pos token.Position
|
pos token.Position
|
||||||
|
where_expr Expr
|
||||||
|
updated_columns []string //for `update set x=y`
|
||||||
|
update_exprs []Expr//for `update`
|
||||||
pub mut:
|
pub mut:
|
||||||
table_name string
|
table_name string
|
||||||
fields []table.Field
|
fields []table.Field
|
||||||
|
|
|
@ -319,8 +319,8 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
||||||
if !c.check_types(field_expr_type, field.typ) {
|
if !c.check_types(field_expr_type, field.typ) {
|
||||||
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
|
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
|
||||||
field_type_sym := c.table.get_type_symbol(field.typ)
|
field_type_sym := c.table.get_type_symbol(field.typ)
|
||||||
c.error('default expression for field `$field.name` ' +
|
c.error('default expression for field `$field.name` ' + 'has type `$field_expr_type_sym.name`, but should be `$field_type_sym.name`',
|
||||||
'has type `$field_expr_type_sym.name`, but should be `$field_type_sym.name`', field.default_expr.position())
|
field.default_expr.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,6 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
||||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||||
if !c.check_types(expr_type, info_field.typ) && expr_type != table.void_type &&
|
if !c.check_types(expr_type, info_field.typ) && expr_type != table.void_type &&
|
||||||
expr_type_sym.kind != .placeholder {
|
expr_type_sym.kind != .placeholder {
|
||||||
|
|
||||||
c.error('!cannot assign $expr_type_sym.kind `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
|
c.error('!cannot assign $expr_type_sym.kind `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
|
||||||
field.pos)
|
field.pos)
|
||||||
}
|
}
|
||||||
|
@ -535,8 +534,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
if infix_expr.op in [.div, .mod] {
|
if infix_expr.op in [.div, .mod] {
|
||||||
if (infix_expr.right is ast.IntegerLiteral &&
|
if (infix_expr.right is ast.IntegerLiteral &&
|
||||||
infix_expr.right.str() == '0') ||
|
infix_expr.right.str() == '0') ||
|
||||||
(infix_expr.right is ast.FloatLiteral &&
|
(infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
||||||
infix_expr.right.str().f64() == 0.0) {
|
|
||||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||||
c.error('$oper by zero', right_pos)
|
c.error('$oper by zero', right_pos)
|
||||||
}
|
}
|
||||||
|
@ -825,7 +823,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
if method := c.table.type_find_method(left_type_sym, method_name) {
|
if method := c.table.type_find_method(left_type_sym, method_name) {
|
||||||
if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test &&
|
if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test &&
|
||||||
left_type_sym.mod != c.mod && left_type_sym.mod != '' { // method.mod != c.mod {
|
left_type_sym.mod != c.mod &&
|
||||||
|
left_type_sym.mod != '' { // method.mod != c.mod {
|
||||||
// If a private method is called outside of the module
|
// If a private method is called outside of the module
|
||||||
// its receiver type is defined in, show an error.
|
// its receiver type is defined in, show an error.
|
||||||
// println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
|
// println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
|
||||||
|
@ -836,7 +835,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
// call_expr.is_mut = true
|
// call_expr.is_mut = true
|
||||||
}
|
}
|
||||||
if method.return_type == table.void_type &&
|
if method.return_type == table.void_type &&
|
||||||
method.ctdefine.len > 0 && method.ctdefine !in c.pref.compile_defines {
|
method.ctdefine.len > 0 &&
|
||||||
|
method.ctdefine !in c.pref.compile_defines {
|
||||||
call_expr.should_be_skipped = true
|
call_expr.should_be_skipped = true
|
||||||
}
|
}
|
||||||
nr_args := if method.args.len == 0 { 0 } else { method.args.len - 1 }
|
nr_args := if method.args.len == 0 { 0 } else { method.args.len - 1 }
|
||||||
|
@ -1020,7 +1020,8 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
call_expr.return_type = f.return_type
|
call_expr.return_type = f.return_type
|
||||||
if f.return_type == table.void_type &&
|
if f.return_type == table.void_type &&
|
||||||
f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines {
|
f.ctdefine.len > 0 &&
|
||||||
|
f.ctdefine !in c.pref.compile_defines {
|
||||||
call_expr.should_be_skipped = true
|
call_expr.should_be_skipped = true
|
||||||
}
|
}
|
||||||
if f.language != .v || call_expr.language != .v {
|
if f.language != .v || call_expr.language != .v {
|
||||||
|
@ -2339,7 +2340,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
||||||
ast.EnumVal { key = expr.val }
|
ast.EnumVal { key = expr.val }
|
||||||
else { key = expr.str() }
|
else { key = expr.str() }
|
||||||
}
|
}
|
||||||
val := if key in branch_exprs { branch_exprs[key] } /**/ else { 0 }
|
val := if key in branch_exprs { branch_exprs[key] } else { 0 }
|
||||||
if val == 1 {
|
if val == 1 {
|
||||||
c.error('match case `$key` is handled more than once', branch.pos)
|
c.error('match case `$key` is handled more than once', branch.pos)
|
||||||
}
|
}
|
||||||
|
@ -2714,7 +2715,6 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) table.Type {
|
||||||
return node.typ
|
return node.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
|
fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
|
||||||
sym := c.table.get_type_symbol(node.table_type)
|
sym := c.table.get_type_symbol(node.table_type)
|
||||||
info := sym.info as table.Struct
|
info := sym.info as table.Struct
|
||||||
|
@ -2736,8 +2736,6 @@ fn (c &Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Positio
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -2774,8 +2772,8 @@ fn (mut c Checker) fn_decl(it ast.FnDecl) {
|
||||||
}
|
}
|
||||||
sym.methods.delete(idx)
|
sym.methods.delete(idx)
|
||||||
//
|
//
|
||||||
c.error('cannot define new methods on non-local `$sym.name` (' +
|
c.error('cannot define new methods on non-local `$sym.name` (' + 'current module is `$c.mod`, `$sym.name` is from `$sym.mod`)',
|
||||||
'current module is `$c.mod`, `$sym.name` is from `$sym.mod`)', it.pos)
|
it.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if it.language == .v {
|
if it.language == .v {
|
||||||
|
|
|
@ -11,38 +11,62 @@ const (
|
||||||
dbtype = 'sqlite'
|
dbtype = 'sqlite'
|
||||||
)
|
)
|
||||||
|
|
||||||
enum SqlExprSide { left right }
|
enum SqlExprSide {
|
||||||
|
left
|
||||||
|
right
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||||
|
g.sql_i = 0
|
||||||
g.writeln('\n\t// sql insert')
|
g.writeln('\n\t// sql insert')
|
||||||
db_name := g.new_tmp_var()
|
db_name := g.new_tmp_var()
|
||||||
g.sql_stmt_name = g.new_tmp_var()
|
g.sql_stmt_name = g.new_tmp_var()
|
||||||
g.write('${dbtype}__DB $db_name = ')
|
g.write('${dbtype}__DB $db_name = ')
|
||||||
g.expr(node.db_expr)
|
g.expr(node.db_expr)
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
mut q := 'insert into $node.table_name ('
|
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("')
|
||||||
|
if node.kind == .insert {
|
||||||
|
g.write('insert into $node.table_name (')
|
||||||
|
} else {
|
||||||
|
g.write('update $node.table_name set ')
|
||||||
|
}
|
||||||
|
if node.kind == .insert {
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if field.name == 'id' {
|
if field.name == 'id' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
q += '$field.name'
|
g.write(field.name)
|
||||||
if i < node.fields.len - 1 {
|
if i < node.fields.len - 1 {
|
||||||
q += ', '
|
g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q += ') values ('
|
g.write( ') values (')
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if field.name == 'id' {
|
if field.name == 'id' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
q += '?${i+0}'
|
g.write('?${i+0}')
|
||||||
if i < node.fields.len - 1 {
|
if i < node.fields.len - 1 {
|
||||||
q += ', '
|
g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q += ')'
|
g.write(')')
|
||||||
println(q)
|
} else if node.kind == .update {
|
||||||
g.writeln('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q"));')
|
for i, col in node.updated_columns {
|
||||||
|
g.write(' $col = ')
|
||||||
|
g.expr_to_sql(node.update_exprs[i])
|
||||||
|
}
|
||||||
|
g.write(' where ')
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if node.kind == .update {
|
||||||
|
g.expr_to_sql(node.where_expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.writeln('"));')
|
||||||
|
if node.kind == .insert {
|
||||||
for i, field in node.fields {
|
for i, field in node.fields {
|
||||||
if field.name == 'id' {
|
if field.name == 'id' {
|
||||||
continue
|
continue
|
||||||
|
@ -51,11 +75,20 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||||
if field.typ == table.string_type {
|
if field.typ == table.string_type {
|
||||||
g.writeln('sqlite3_bind_text($g.sql_stmt_name, ${i+0}, ${x}.str, ${x}.len, 0);')
|
g.writeln('sqlite3_bind_text($g.sql_stmt_name, ${i+0}, ${x}.str, ${x}.len, 0);')
|
||||||
} else {
|
} else {
|
||||||
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i+0}, $x); //insertl')
|
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i+0}, $x); // stmt')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if node.kind == .update {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump all sql parameters generated by our custom expr handler
|
||||||
|
binds := g.sql_buf.str()
|
||||||
|
g.sql_buf = strings.new_builder(100)
|
||||||
|
g.writeln(binds)
|
||||||
g.writeln('sqlite3_step($g.sql_stmt_name);')
|
g.writeln('sqlite3_step($g.sql_stmt_name);')
|
||||||
g.writeln('puts(sqlite3_errmsg(${db_name}.conn));')
|
g.writeln('if (strcmp(sqlite3_errmsg(${db_name}.conn), "not an error") != 0) puts(sqlite3_errmsg(${db_name}.conn)); ')
|
||||||
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
|
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +140,7 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
||||||
binds := g.sql_buf.str()
|
binds := g.sql_buf.str()
|
||||||
g.sql_buf = strings.new_builder(100)
|
g.sql_buf = strings.new_builder(100)
|
||||||
g.writeln(binds)
|
g.writeln(binds)
|
||||||
g.writeln('puts(sqlite3_errmsg(${db_name}.conn));')
|
g.writeln('if (strcmp(sqlite3_errmsg(${db_name}.conn), "not an error") != 0) puts(sqlite3_errmsg(${db_name}.conn)); ')
|
||||||
//
|
//
|
||||||
if node.is_count {
|
if node.is_count {
|
||||||
g.writeln('$cur_line ${dbtype}__get_int_from_stmt($g.sql_stmt_name);')
|
g.writeln('$cur_line ${dbtype}__get_int_from_stmt($g.sql_stmt_name);')
|
||||||
|
@ -177,12 +210,10 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
||||||
|
|
||||||
fn (mut g Gen) sql_bind_int(val string) {
|
fn (mut g Gen) sql_bind_int(val string) {
|
||||||
g.sql_buf.writeln('sqlite3_bind_int($g.sql_stmt_name, $g.sql_i, $val);')
|
g.sql_buf.writeln('sqlite3_bind_int($g.sql_stmt_name, $g.sql_i, $val);')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_bind_string(val string, len string) {
|
fn (mut g Gen) sql_bind_string(val, len string) {
|
||||||
g.sql_buf.writeln('sqlite3_bind_text($g.sql_stmt_name, $g.sql_i, $val, $len, 0);')
|
g.sql_buf.writeln('sqlite3_bind_text($g.sql_stmt_name, $g.sql_i, $val, $len, 0);')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||||
|
@ -221,7 +252,11 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||||
// true/false literals were added to Sqlite 3.23 (2018-04-02)
|
// true/false literals were added to Sqlite 3.23 (2018-04-02)
|
||||||
// but lots of apps/distros use older sqlite (e.g. Ubuntu 18.04 LTS )
|
// but lots of apps/distros use older sqlite (e.g. Ubuntu 18.04 LTS )
|
||||||
g.inc_sql_i()
|
g.inc_sql_i()
|
||||||
g.sql_bind_int(if it.val { '1' } else { '0' })
|
g.sql_bind_int(if it.val {
|
||||||
|
'1'
|
||||||
|
} else {
|
||||||
|
'0'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
// `name == user_name` => `name == ?1`
|
// `name == user_name` => `name == ?1`
|
||||||
|
@ -235,11 +270,9 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||||
typ := info.typ
|
typ := info.typ
|
||||||
if typ == table.string_type {
|
if typ == table.string_type {
|
||||||
g.sql_bind_string('${expr.name}.str', '${expr.name}.len')
|
g.sql_bind_string('${expr.name}.str', '${expr.name}.len')
|
||||||
}
|
} else if typ == table.int_type {
|
||||||
else if typ == table.int_type {
|
|
||||||
g.sql_bind_int(expr.name)
|
g.sql_bind_int(expr.name)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
verror('bad sql type $typ')
|
verror('bad sql type $typ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,11 +60,9 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
||||||
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_type: table_type
|
table_type: table_type
|
||||||
where_expr: where_expr
|
where_expr: where_expr
|
||||||
has_where: has_where
|
has_where: has_where
|
||||||
//fields: fields
|
|
||||||
is_array: !query_one
|
is_array: !query_one
|
||||||
pos: pos
|
pos: pos
|
||||||
}
|
}
|
||||||
|
@ -109,6 +107,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||||
}
|
}
|
||||||
n = p.check_name() // into
|
n = p.check_name() // into
|
||||||
mut updated_columns := []string{}
|
mut updated_columns := []string{}
|
||||||
|
mut update_exprs := []ast.Expr{cap: 5}
|
||||||
if kind == .insert && n != 'into' {
|
if kind == .insert && n != 'into' {
|
||||||
p.error('expecting `into`')
|
p.error('expecting `into`')
|
||||||
} else if kind == .update {
|
} else if kind == .update {
|
||||||
|
@ -118,9 +117,10 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||||
column := p.check_name()
|
column := p.check_name()
|
||||||
updated_columns << column
|
updated_columns << column
|
||||||
p.check(.assign)
|
p.check(.assign)
|
||||||
p.expr(0)
|
update_exprs << p.expr(0)
|
||||||
}
|
}
|
||||||
mut table_type := table.Type(0)
|
mut table_type := table.Type(0)
|
||||||
|
mut where_expr := ast.Expr{}
|
||||||
if kind == .insert {
|
if kind == .insert {
|
||||||
table_type = p.parse_type() // `User`
|
table_type = p.parse_type() // `User`
|
||||||
sym := p.table.get_type_symbol(table_type)
|
sym := p.table.get_type_symbol(table_type)
|
||||||
|
@ -131,7 +131,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||||
idx := p.table.find_type_idx(table_name)
|
idx := p.table.find_type_idx(table_name)
|
||||||
table_type = table.new_type(idx)
|
table_type = table.new_type(idx)
|
||||||
p.check_sql_keyword('where')
|
p.check_sql_keyword('where')
|
||||||
p.expr(0)
|
where_expr = p.expr(0)
|
||||||
}
|
}
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
return ast.SqlStmt{
|
return ast.SqlStmt{
|
||||||
|
@ -140,6 +140,10 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||||
table_type: table_type
|
table_type: table_type
|
||||||
object_var_name: inserted_var_name
|
object_var_name: inserted_var_name
|
||||||
pos: pos
|
pos: pos
|
||||||
|
updated_columns: updated_columns
|
||||||
|
update_exprs: update_exprs
|
||||||
|
kind: kind
|
||||||
|
where_expr: where_expr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue