orm: add type detection of db (#8756)
parent
94acc27ee6
commit
4bdbb0cfa8
|
@ -17,7 +17,62 @@ enum SqlExprSide {
|
||||||
right
|
right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SqlType {
|
||||||
|
sqlite3
|
||||||
|
mysql
|
||||||
|
psql
|
||||||
|
unknown
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
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.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()
|
||||||
|
@ -58,7 +113,7 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||||
} else if node.kind == .update {
|
} else if node.kind == .update {
|
||||||
for i, col in node.updated_columns {
|
for i, col in node.updated_columns {
|
||||||
g.write(' $col = ')
|
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 {
|
if i < node.updated_columns.len - 1 {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
|
@ -68,7 +123,7 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||||
g.write(' WHERE ')
|
g.write(' WHERE ')
|
||||||
}
|
}
|
||||||
if node.kind == .update || node.kind == .delete {
|
if node.kind == .update || node.kind == .delete {
|
||||||
g.expr_to_sql(node.where_expr)
|
g.expr_to_sql(node.where_expr, typ)
|
||||||
}
|
}
|
||||||
g.writeln('"));')
|
g.writeln('"));')
|
||||||
if node.kind == .insert {
|
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);')
|
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
|
g.sql_i = 0
|
||||||
/*
|
/*
|
||||||
`nr_users := sql db { ... }` =>
|
`nr_users := sql db { ... }` =>
|
||||||
```
|
```
|
||||||
sql_init_stmt()
|
sql_init_stmt()
|
||||||
sql_bind_int()
|
sqlite3_bind_int()
|
||||||
sql_bind_string()
|
sqlite3_bind_string()
|
||||||
...
|
...
|
||||||
int nr_users = get_int(stmt)
|
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('sqlite3_stmt* $g.sql_stmt_name = ${c.dbtype}__DB_init_stmt($db_name, _SLIT("')
|
||||||
g.write(sql_query)
|
g.write(sql_query)
|
||||||
if node.has_where && node.where_expr is ast.InfixExpr {
|
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 {
|
if node.has_order {
|
||||||
g.write(' ORDER BY ')
|
g.write(' ORDER BY ')
|
||||||
g.sql_side = .left
|
g.sql_side = .left
|
||||||
g.expr_to_sql(node.order_expr)
|
g.expr_to_sql(node.order_expr, sql_typ)
|
||||||
if node.has_desc {
|
if node.has_desc {
|
||||||
g.write(' 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 {
|
if node.has_limit {
|
||||||
g.write(' LIMIT ')
|
g.write(' LIMIT ')
|
||||||
g.sql_side = .right
|
g.sql_side = .right
|
||||||
g.expr_to_sql(node.limit_expr)
|
g.expr_to_sql(node.limit_expr, sql_typ)
|
||||||
}
|
}
|
||||||
if node.has_offset {
|
if node.has_offset {
|
||||||
g.write(' OFFSET ')
|
g.write(' OFFSET ')
|
||||||
g.sql_side = .right
|
g.sql_side = .right
|
||||||
g.expr_to_sql(node.offset_expr)
|
g.expr_to_sql(node.offset_expr, sql_typ)
|
||||||
}
|
}
|
||||||
g.writeln('"));')
|
g.writeln('"));')
|
||||||
// Dump all sql parameters generated by our custom expr handler
|
// 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);')
|
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);')
|
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),
|
// 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()
|
// 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 {
|
match expr {
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
g.sql_side = .left
|
g.sql_side = .left
|
||||||
g.expr_to_sql(expr.left)
|
g.expr_to_sql(expr.left, typ)
|
||||||
match expr.op {
|
match expr.op {
|
||||||
.eq { g.write(' = ') }
|
.eq { g.write(' = ') }
|
||||||
.gt { g.write(' > ') }
|
.gt { g.write(' > ') }
|
||||||
|
@ -316,22 +387,22 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
g.sql_side = .right
|
g.sql_side = .right
|
||||||
g.expr_to_sql(expr.right)
|
g.expr_to_sql(expr.right, typ)
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
// g.write("'$it.val'")
|
// g.write("'$it.val'")
|
||||||
g.inc_sql_i()
|
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 {
|
ast.IntegerLiteral {
|
||||||
g.inc_sql_i()
|
g.inc_sql_i()
|
||||||
g.sql_bind_int(expr.val)
|
g.sql_bind_int(expr.val, typ)
|
||||||
}
|
}
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
// 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 expr.val { '1' } else { '0' })
|
g.sql_bind_int(if expr.val { '1' } else { '0' }, typ)
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
// `name == user_name` => `name == ?1`
|
// `name == user_name` => `name == ?1`
|
||||||
|
@ -342,13 +413,13 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||||
} else {
|
} else {
|
||||||
g.inc_sql_i()
|
g.inc_sql_i()
|
||||||
info := expr.info as ast.IdentVar
|
info := expr.info as ast.IdentVar
|
||||||
typ := info.typ
|
ityp := info.typ
|
||||||
if typ == table.string_type {
|
if ityp == table.string_type {
|
||||||
g.sql_bind_string('${expr.name}.str', '${expr.name}.len')
|
g.sql_bind_string('${expr.name}.str', '${expr.name}.len', typ)
|
||||||
} else if typ == table.int_type {
|
} else if ityp == table.int_type {
|
||||||
g.sql_bind_int(expr.name)
|
g.sql_bind_int(expr.name, typ)
|
||||||
} else {
|
} 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')
|
verror('orm selector not ident')
|
||||||
}
|
}
|
||||||
ident := expr.expr as ast.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 {
|
} else {
|
||||||
verror('bad sql type=$expr.typ selector expr=$expr.field_name')
|
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.sql_i++
|
||||||
g.write('?$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