orm: select many

pull/5404/head
Alexander Medvednikov 2020-06-17 14:18:32 +02:00
parent effa0061e8
commit 6066414afa
4 changed files with 56 additions and 11 deletions

View File

@ -25,7 +25,7 @@ fn test_orm_sqlite() {
name := '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, age) values ('Peter', 31)")
db.exec("insert into User (name) values ('Kate')")
nr_all_users := sql db {
select count from User
@ -57,6 +57,15 @@ fn test_orm_sqlite() {
assert user.name == 'Sam'
assert user.id == 1
assert user.age == 29
//
users := sql db {
select from User where id > 0
}
println(users)
assert users.len == 3
assert users[0].name == 'Sam'
assert users[1].name == 'Peter'
assert users[1].age == 31
}

View File

@ -44,7 +44,6 @@ pub struct ExprStmt {
pub:
expr Expr
pos token.Position
// is used for `x++` in `for x:=1; ; x++`
is_expr bool
pub mut:
typ table.Type
@ -567,6 +566,7 @@ pub struct Attr {
pub:
name string
}
pub fn (attrs []Attr) contains(attr Attr) bool {
for a in attrs {
if attr.name == a.name {
@ -816,6 +816,7 @@ pub:
where_expr Expr
has_where bool
fields []table.Field
is_array bool
}
[inline]

View File

@ -65,9 +65,26 @@ fn (mut g Gen) sql_expr(node ast.SqlExpr) {
} 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);')
styp := g.typ(node.typ)
mut elem_type_str := ''
if node.is_array {
sym := g.table.get_type_symbol(node.typ)
info := sym.info as table.Array
elem_type_str = g.typ(info.elem_type)
// array_User array_tmp;
// for { User tmp; ... array_tmp << tmp; }
g.writeln('$styp ${tmp}_array = __new_array(0, 10, sizeof($elem_type_str));')
g.writeln('while (1) {')
g.writeln('\t$elem_type_str $tmp;')
} else {
// `User tmp;`
g.writeln('$styp $tmp;')
}
//
g.writeln('int _step_res$tmp = sqlite3_step($g.sql_stmt_name);')
if node.is_array {
g.writeln('\tif (_step_res$tmp == SQLITE_DONE) break;')
}
for i, field in node.fields {
mut func := 'sqlite3_column_int'
if field.typ == table.string_type {
@ -77,10 +94,18 @@ fn (mut g Gen) sql_expr(node ast.SqlExpr) {
g.writeln('${tmp}.$field.name = ${func}($g.sql_stmt_name, $i);')
}
}
if node.is_array {
g.writeln('\t array_push(&${tmp}_array, _MOV(($elem_type_str[]){ $tmp }));')
g.writeln('} // for')
}
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
if node.is_array {
g.writeln('$cur_line ${tmp}_array; ') // `array_User users = tmp_array;`
} else {
g.writeln('$cur_line $tmp; ') // `User user = tmp;`
}
}
}
fn (mut g Gen) expr_to_sql(expr ast.Expr) {
// Custom handling for infix exprs (since we need e.g. `and` instead of `&&` in SQL queries),
@ -93,6 +118,7 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
g.expr_to_sql(it.left)
match it.op {
.eq { g.write(' = ') }
.gt { g.write(' > ') }
.and { g.write(' and ') }
else {}
}

View File

@ -25,6 +25,7 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
table_name := sym.name
mut where_expr := ast.Expr{}
has_where := p.tok.kind == .name && p.tok.lit == 'where'
mut query_one := false // one object is returned, not an array
if has_where {
p.next()
where_expr = p.expr(0)
@ -34,11 +35,18 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
if e.op == .eq && e.left is ast.Ident {
ident := e.left as ast.Ident
if ident.name == 'id' {
// TODO optional
query_one = true
typ = table_type
// typ = table_type.set_flag(.optional)
}
}
}
}
if !query_one && !is_count {
// return an array
typ = table.new_type(p.table.find_or_register_array(table_type, 1, p.mod))
}
p.check(.rcbr)
// /////////
// Register this type's fields as variables so they can be used in `where`
@ -86,5 +94,6 @@ fn (mut p Parser) sql_expr() ast.SqlExpr {
where_expr: where_expr
has_where: has_where
fields: fields
is_array: !query_one
}
}