orm: select where id = x
parent
ddb1770af2
commit
fb5cae7376
|
@ -3,27 +3,28 @@
|
|||
//import term
|
||||
import sqlite
|
||||
|
||||
struct Modules {
|
||||
struct Module {
|
||||
id int
|
||||
user_id int
|
||||
name string
|
||||
url string
|
||||
//name string
|
||||
//url string
|
||||
//nr_downloads int
|
||||
}
|
||||
|
||||
struct User {
|
||||
id int
|
||||
age int
|
||||
name string
|
||||
}
|
||||
|
||||
fn test_orm_sqlite() {
|
||||
db := sqlite.connect(':memory:') or { panic(err) }
|
||||
db.exec("drop table if exists User")
|
||||
db.exec("create table User (id integer primary key, name text default '');")
|
||||
db.exec("create table User (id integer primary key, age int default 0, name text default '');")
|
||||
|
||||
name := 'sam'
|
||||
|
||||
db.exec("insert into User (name) values ('Sam')")
|
||||
db.exec("insert into User (name, age) values ('Sam', 29)")
|
||||
db.exec("insert into User (name) values ('Peter')")
|
||||
db.exec("insert into User (name) values ('Kate')")
|
||||
nr_all_users := sql db {
|
||||
|
@ -48,6 +49,14 @@ fn test_orm_sqlite() {
|
|||
select count from User where id == 1 && name == name
|
||||
}
|
||||
println('nr_sams=$nr_sams')
|
||||
//
|
||||
user := sql db {
|
||||
select from User where id == 1
|
||||
}
|
||||
println(user)
|
||||
assert user.name == 'Sam'
|
||||
assert user.id == 1
|
||||
assert user.age == 29
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,10 +15,13 @@ fn test_sb() {
|
|||
assert sb.len == 2
|
||||
assert sb.str() == 'ab'
|
||||
///
|
||||
$if !windows {
|
||||
// TODO msvc bug
|
||||
sb = strings.new_builder(10)
|
||||
sb.write('123456')
|
||||
assert sb.cut_last(2) == '56'
|
||||
assert sb.str() == '1234'
|
||||
}
|
||||
///
|
||||
/*
|
||||
sb = strings.new_builder(10)
|
||||
|
|
|
@ -9,11 +9,11 @@ import v.errors
|
|||
|
||||
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
|
||||
|
||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr |
|
||||
CastExpr | CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr |
|
||||
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | MapInit | MatchExpr | None |
|
||||
OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr |
|
||||
StringInterLiteral | StringLiteral | StructInit | Type | TypeOf
|
||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr | CharLiteral |
|
||||
ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr |
|
||||
InfixExpr | IntegerLiteral | Likely | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr |
|
||||
PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
||||
StructInit | Type | TypeOf
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl |
|
||||
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||
|
@ -44,7 +44,6 @@ pub struct ExprStmt {
|
|||
pub:
|
||||
expr Expr
|
||||
pos token.Position
|
||||
// treat like expr (dont add trailing `;`)
|
||||
// is used for `x++` in `for x:=1; ; x++`
|
||||
is_expr bool
|
||||
pub mut:
|
||||
|
@ -808,6 +807,7 @@ pub:
|
|||
table_name string
|
||||
where_expr Expr
|
||||
has_where bool
|
||||
fields []table.Field
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
|
|
@ -1307,8 +1307,9 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
if right_type_sym0.kind == .multi_return {
|
||||
assign_stmt.right_types = right_type_sym0.mr_info().types
|
||||
right_len = assign_stmt.right_types.len
|
||||
} else if right_type0 == table.void_type {
|
||||
right_len = 0
|
||||
}
|
||||
else if right_type0 == table.void_type { right_len=0 }
|
||||
}
|
||||
if assign_stmt.left.len != right_len {
|
||||
if right_first is ast.CallExpr {
|
||||
|
@ -1338,7 +1339,9 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
if is_decl {
|
||||
left_type = c.table.mktyp(right_type)
|
||||
// we are unwrapping here instead if check_expr_opt_call currently
|
||||
if left_type.has_flag(.optional) { left_type = left_type.clear_flag(.optional) }
|
||||
if left_type.has_flag(.optional) {
|
||||
left_type = left_type.clear_flag(.optional)
|
||||
}
|
||||
} else {
|
||||
// Make sure the variable is mutable
|
||||
c.fail_if_immutable(left)
|
||||
|
@ -1353,9 +1356,10 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
if assign_stmt.op !in [.assign, .decl_assign] {
|
||||
c.error('cannot modify blank `_` identifier', it.pos)
|
||||
}
|
||||
} else {
|
||||
if is_decl {
|
||||
c.check_valid_snake_case(it.name, 'variable name', it.pos)
|
||||
}
|
||||
else {
|
||||
if is_decl { c.check_valid_snake_case(it.name, 'variable name', it.pos) }
|
||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
||||
mut ident_var_info := it.var_info()
|
||||
ident_var_info.typ = left_type
|
||||
|
@ -1366,12 +1370,12 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
ast.PrefixExpr {
|
||||
// Do now allow `*x = y` outside `unsafe`
|
||||
if it.op == .mul && !c.inside_unsafe {
|
||||
c.error('modifying variables via deferencing can only be done in `unsafe` blocks', assign_stmt.pos)
|
||||
c.error('modifying variables via deferencing can only be done in `unsafe` blocks',
|
||||
assign_stmt.pos)
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
|
||||
left_type_unwrapped := c.unwrap_generic(left_type)
|
||||
right_type_unwrapped := c.unwrap_generic(right_type)
|
||||
left_sym := c.table.get_type_symbol(left_type_unwrapped)
|
||||
|
@ -1381,9 +1385,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
.assign {} // No need to do single side check for =. But here put it first for speed.
|
||||
.plus_assign {
|
||||
if !left_sym.is_number() && left_type != table.string_type && !left_sym.is_pointer() {
|
||||
c.error('operator += not defined on left operand type `$left_sym.name`', left.position())
|
||||
c.error('operator += not defined on left operand type `$left_sym.name`',
|
||||
left.position())
|
||||
} else if !right_sym.is_number() && right_type != table.string_type && !right_sym.is_pointer() {
|
||||
c.error('operator += not defined on right operand type `$right_sym.name`', right.position())
|
||||
c.error('operator += not defined on right operand type `$right_sym.name`',
|
||||
right.position())
|
||||
}
|
||||
if right is ast.IntegerLiteral && right.str().int() == 1 {
|
||||
c.error('use `++` instead of `+= 1`', assign_stmt.pos)
|
||||
|
@ -1391,9 +1397,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
.minus_assign {
|
||||
if !left_sym.is_number() && !left_sym.is_pointer() {
|
||||
c.error('operator -= not defined on left operand type `$left_sym.name`', left.position())
|
||||
c.error('operator -= not defined on left operand type `$left_sym.name`',
|
||||
left.position())
|
||||
} else if !right_sym.is_number() && !right_sym.is_pointer() {
|
||||
c.error('operator -= not defined on right operand type `$right_sym.name`', right.position())
|
||||
c.error('operator -= not defined on right operand type `$right_sym.name`',
|
||||
right.position())
|
||||
}
|
||||
if right is ast.IntegerLiteral && right.str().int() == 1 {
|
||||
c.error('use `--` instead of `-= 1`', assign_stmt.pos)
|
||||
|
@ -1973,10 +1981,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
return table.u32_type
|
||||
}
|
||||
ast.SqlExpr {
|
||||
if it.has_where {
|
||||
c.expr(it.where_expr)
|
||||
}
|
||||
return it.typ
|
||||
return c.sql_expr(it)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
if it.language == .c {
|
||||
|
@ -2564,6 +2569,13 @@ fn (c &Checker) fileis(s string) bool {
|
|||
return c.file.path.contains(s)
|
||||
}
|
||||
|
||||
fn (mut c Checker) sql_expr(node ast.SqlExpr) table.Type {
|
||||
if node.has_where {
|
||||
c.expr(node.where_expr)
|
||||
}
|
||||
return node.typ
|
||||
}
|
||||
|
||||
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
|
||||
// loop thru each generic type and generate a function
|
||||
|
|
|
@ -5,6 +5,7 @@ module gen
|
|||
|
||||
import v.ast
|
||||
import strings
|
||||
import v.table
|
||||
|
||||
// pg,mysql etc
|
||||
const (
|
||||
|
@ -26,8 +27,17 @@ fn (mut g Gen) sql_expr(node ast.SqlExpr) {
|
|||
cur_line := g.go_before_stmt(0)
|
||||
mut q := 'select '
|
||||
if node.is_count {
|
||||
// select count(*) from User
|
||||
// `select count(*) from User`
|
||||
q += 'count(*) from $node.table_name'
|
||||
} else {
|
||||
// `select id, name, country from User`
|
||||
for i, field in node.fields {
|
||||
q += '$field.name'
|
||||
if i < node.fields.len - 1 {
|
||||
q += ', '
|
||||
}
|
||||
}
|
||||
q += ' from $node.table_name'
|
||||
}
|
||||
if node.has_where {
|
||||
q += ' where '
|
||||
|
@ -37,7 +47,7 @@ fn (mut g Gen) sql_expr(node ast.SqlExpr) {
|
|||
db_name := g.new_tmp_var()
|
||||
g.writeln('\n\t// sql')
|
||||
// g.write('${dbtype}__DB $db_name = *(${dbtype}__DB*)${node.db_var_name}.data;')
|
||||
g.write('${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($db_name, tos_lit("$q')
|
||||
if node.has_where && node.where_expr is ast.InfixExpr {
|
||||
|
@ -49,7 +59,27 @@ fn (mut g Gen) sql_expr(node ast.SqlExpr) {
|
|||
g.sql_buf = strings.new_builder(100)
|
||||
g.writeln(binds)
|
||||
g.writeln('puts(sqlite3_errmsg(${db_name}.conn));')
|
||||
//
|
||||
if node.is_count {
|
||||
g.writeln('$cur_line ${dbtype}__get_int_from_stmt($g.sql_stmt_name);')
|
||||
} else {
|
||||
// `user := sql db { select from User where id = 1 }`
|
||||
tmp := g.new_tmp_var()
|
||||
g.write(g.typ(node.typ))
|
||||
g.writeln(' $tmp;')
|
||||
g.writeln('sqlite3_step($g.sql_stmt_name);')
|
||||
for i, field in node.fields {
|
||||
mut func := 'sqlite3_column_int'
|
||||
if field.typ == table.string_type {
|
||||
func = 'sqlite3_column_text'
|
||||
g.writeln('${tmp}.$field.name = tos_clone(${func}($g.sql_stmt_name, $i));')
|
||||
} else {
|
||||
g.writeln('${tmp}.$field.name = ${func}($g.sql_stmt_name, $i);')
|
||||
}
|
||||
}
|
||||
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
|
||||
g.writeln('$cur_line $tmp; ') // `User user = tmp;`
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
||||
|
|
|
@ -28,6 +28,16 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
|
|||
if has_where {
|
||||
p.next()
|
||||
where_expr = p.expr(0)
|
||||
// `id == x` means that a single object is returned
|
||||
if !is_count && where_expr is ast.InfixExpr {
|
||||
e := where_expr as ast.InfixExpr
|
||||
if e.op == .eq && e.left is ast.Ident {
|
||||
ident := e.left as ast.Ident
|
||||
if ident.name == 'id' {
|
||||
typ = table_type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.check(.rcbr)
|
||||
// /////////
|
||||
|
@ -75,5 +85,6 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
|
|||
table_name: table_name
|
||||
where_expr: where_expr
|
||||
has_where: has_where
|
||||
fields: fields
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue