1
0
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:
Louis Schmieder 2021-02-15 16:14:39 +01:00 committed by GitHub
parent 94acc27ee6
commit 4bdbb0cfa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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