mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
orm: add type detection of db (#8756)
This commit is contained in:
parent
94acc27ee6
commit
4bdbb0cfa8
@ -17,7 +17,62 @@ enum SqlExprSide {
|
||||
right
|
||||
}
|
||||
|
||||
enum SqlType {
|
||||
sqlite3
|
||||
mysql
|
||||
psql
|
||||
unknown
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
typ := g.parse_db_type(node.db_expr)
|
||||
match typ {
|
||||
.sqlite3 {
|
||||
g.sqlite3_stmt(node, typ)
|
||||
}
|
||||
else {
|
||||
verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
typ := g.parse_db_type(node.db_expr)
|
||||
match typ {
|
||||
.sqlite3 {
|
||||
g.sqlite3_select_expr(node, sub, line, typ)
|
||||
}
|
||||
else {
|
||||
verror('This database type `$typ` is not implemented yet in orm') // TODO add better error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_bind_int(val string, typ SqlType) {
|
||||
match typ {
|
||||
.sqlite3 {
|
||||
g.sqlite3_bind_int(val)
|
||||
}
|
||||
else {
|
||||
// add error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_bind_string(val string, len string, typ SqlType) {
|
||||
match typ {
|
||||
.sqlite3 {
|
||||
g.sqlite3_bind_string(val, len)
|
||||
}
|
||||
else {
|
||||
// add error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sqlite3
|
||||
|
||||
fn (mut g Gen) sqlite3_stmt(node ast.SqlStmt, typ SqlType) {
|
||||
g.sql_i = 0
|
||||
g.writeln('\n\t// sql insert')
|
||||
db_name := g.new_tmp_var()
|
||||
@ -58,7 +113,7 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
} else if node.kind == .update {
|
||||
for i, col in node.updated_columns {
|
||||
g.write(' $col = ')
|
||||
g.expr_to_sql(node.update_exprs[i])
|
||||
g.expr_to_sql(node.update_exprs[i], typ)
|
||||
if i < node.updated_columns.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
@ -68,7 +123,7 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
g.write(' WHERE ')
|
||||
}
|
||||
if node.kind == .update || node.kind == .delete {
|
||||
g.expr_to_sql(node.where_expr)
|
||||
g.expr_to_sql(node.where_expr, typ)
|
||||
}
|
||||
g.writeln('"));')
|
||||
if node.kind == .insert {
|
||||
@ -106,14 +161,14 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
g.writeln('\tsqlite3_finalize($g.sql_stmt_name);')
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_typ SqlType) {
|
||||
g.sql_i = 0
|
||||
/*
|
||||
`nr_users := sql db { ... }` =>
|
||||
```
|
||||
sql_init_stmt()
|
||||
sql_bind_int()
|
||||
sql_bind_string()
|
||||
sqlite3_bind_int()
|
||||
sqlite3_bind_string()
|
||||
...
|
||||
int nr_users = get_int(stmt)
|
||||
```
|
||||
@ -152,12 +207,12 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
g.write('sqlite3_stmt* $g.sql_stmt_name = ${c.dbtype}__DB_init_stmt($db_name, _SLIT("')
|
||||
g.write(sql_query)
|
||||
if node.has_where && node.where_expr is ast.InfixExpr {
|
||||
g.expr_to_sql(node.where_expr)
|
||||
g.expr_to_sql(node.where_expr, sql_typ)
|
||||
}
|
||||
if node.has_order {
|
||||
g.write(' ORDER BY ')
|
||||
g.sql_side = .left
|
||||
g.expr_to_sql(node.order_expr)
|
||||
g.expr_to_sql(node.order_expr, sql_typ)
|
||||
if node.has_desc {
|
||||
g.write(' DESC ')
|
||||
}
|
||||
@ -167,12 +222,12 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
if node.has_limit {
|
||||
g.write(' LIMIT ')
|
||||
g.sql_side = .right
|
||||
g.expr_to_sql(node.limit_expr)
|
||||
g.expr_to_sql(node.limit_expr, sql_typ)
|
||||
}
|
||||
if node.has_offset {
|
||||
g.write(' OFFSET ')
|
||||
g.sql_side = .right
|
||||
g.expr_to_sql(node.offset_expr)
|
||||
g.expr_to_sql(node.offset_expr, sql_typ)
|
||||
}
|
||||
g.writeln('"));')
|
||||
// Dump all sql parameters generated by our custom expr handler
|
||||
@ -283,15 +338,31 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_bind_int(val string) {
|
||||
fn (mut g Gen) sqlite3_bind_int(val string) {
|
||||
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) sqlite3_bind_string(val string, len string) {
|
||||
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) {
|
||||
// mysql
|
||||
|
||||
fn (mut g Gen) mysql_stmt(node ast.SqlStmt) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) mysql_bind_int(val string) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) mysql_bind_string(val string, len string) {
|
||||
}
|
||||
|
||||
// utils
|
||||
|
||||
fn (mut g Gen) expr_to_sql(expr ast.Expr, typ SqlType) {
|
||||
// Custom handling for infix exprs (since we need e.g. `and` instead of `&&` in SQL queries),
|
||||
// strings. Everything else (like numbers, a.b) is handled by g.expr()
|
||||
//
|
||||
@ -300,7 +371,7 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||
match expr {
|
||||
ast.InfixExpr {
|
||||
g.sql_side = .left
|
||||
g.expr_to_sql(expr.left)
|
||||
g.expr_to_sql(expr.left, typ)
|
||||
match expr.op {
|
||||
.eq { g.write(' = ') }
|
||||
.gt { g.write(' > ') }
|
||||
@ -316,22 +387,22 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||
else {}
|
||||
}
|
||||
g.sql_side = .right
|
||||
g.expr_to_sql(expr.right)
|
||||
g.expr_to_sql(expr.right, typ)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
// g.write("'$it.val'")
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_string('"$expr.val"', expr.val.len.str())
|
||||
g.sql_bind_string('"$expr.val"', expr.val.len.str(), typ)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_int(expr.val)
|
||||
g.sql_bind_int(expr.val, typ)
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
// 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 )
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_int(if expr.val { '1' } else { '0' })
|
||||
g.sql_bind_int(if expr.val { '1' } else { '0' }, typ)
|
||||
}
|
||||
ast.Ident {
|
||||
// `name == user_name` => `name == ?1`
|
||||
@ -342,13 +413,13 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||
} else {
|
||||
g.inc_sql_i()
|
||||
info := expr.info as ast.IdentVar
|
||||
typ := info.typ
|
||||
if typ == table.string_type {
|
||||
g.sql_bind_string('${expr.name}.str', '${expr.name}.len')
|
||||
} else if typ == table.int_type {
|
||||
g.sql_bind_int(expr.name)
|
||||
ityp := info.typ
|
||||
if ityp == table.string_type {
|
||||
g.sql_bind_string('${expr.name}.str', '${expr.name}.len', typ)
|
||||
} else if ityp == table.int_type {
|
||||
g.sql_bind_int(expr.name, typ)
|
||||
} else {
|
||||
verror('bad sql type=$typ ident_name=$expr.name')
|
||||
verror('bad sql type=$ityp ident_name=$expr.name')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +430,7 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||
verror('orm selector not ident')
|
||||
}
|
||||
ident := expr.expr as ast.Ident
|
||||
g.sql_bind_int(ident.name + '.' + expr.field_name)
|
||||
g.sql_bind_int(ident.name + '.' + expr.field_name, typ)
|
||||
} else {
|
||||
verror('bad sql type=$expr.typ selector expr=$expr.field_name')
|
||||
}
|
||||
@ -380,3 +451,31 @@ fn (mut g Gen) inc_sql_i() {
|
||||
g.sql_i++
|
||||
g.write('?$g.sql_i')
|
||||
}
|
||||
|
||||
fn (mut g Gen) parse_db_type(expr ast.Expr) SqlType {
|
||||
match expr {
|
||||
ast.Ident {
|
||||
if expr.info is ast.IdentVar {
|
||||
return g.parse_db_from_type_string(g.table.get_type_name(expr.info.typ))
|
||||
}
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
return g.parse_db_from_type_string(g.table.get_type_name(expr.typ))
|
||||
}
|
||||
else {
|
||||
return .unknown
|
||||
}
|
||||
}
|
||||
return .unknown
|
||||
}
|
||||
|
||||
fn (mut g Gen) parse_db_from_type_string(name string) SqlType {
|
||||
match name {
|
||||
'sqlite.DB' {
|
||||
return .sqlite3
|
||||
}
|
||||
else {
|
||||
return .unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user