orm: fix `column == var`; limit 1; vweb: @footer
parent
73296e486a
commit
deb09d95b0
|
@ -9,6 +9,7 @@ import os
|
|||
// / customizing the look & feel of the assertions results easier,
|
||||
// / since it is done in normal V code, instead of in embedded C ...
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// TODO copy pasta builtin.v fn ___print_assert_failure
|
||||
fn cb_assertion_failed(i &VAssertMetaInfo) {
|
||||
// color_on := term.can_show_color_on_stderr()
|
||||
use_relative_paths := match os.getenv('VERROR_PATHS') {
|
||||
|
@ -25,7 +26,12 @@ fn cb_assertion_failed(i &VAssertMetaInfo) {
|
|||
eprintln('Source : ${i.src}')
|
||||
if i.op.len > 0 && i.op != 'call' {
|
||||
eprintln(' left value: ${i.llabel} = ${i.lvalue}')
|
||||
eprintln(' right value: ${i.rlabel} = ${i.rvalue}')
|
||||
if i.rlabel == i.rvalue {
|
||||
eprintln(' right value: $i.rlabel')
|
||||
}
|
||||
else {
|
||||
eprintln(' right value: ${i.rlabel} = ${i.rvalue}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -239,6 +239,11 @@ fn __print_assert_failure(i &VAssertMetaInfo) {
|
|||
eprintln('${i.fpath}:${i.line_nr+1}: FAIL: fn ${i.fn_name}: assert ${i.src}')
|
||||
if i.op.len > 0 && i.op != 'call' {
|
||||
eprintln(' left value: ${i.llabel} = ${i.lvalue}')
|
||||
eprintln(' right value: ${i.rlabel} = ${i.rvalue}')
|
||||
if i.rlabel == i.rvalue {
|
||||
eprintln(' right value: $i.rlabel')
|
||||
}
|
||||
else {
|
||||
eprintln(' right value: ${i.rlabel} = ${i.rvalue}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ fn test_orm_sqlite() {
|
|||
db.exec("drop table if exists User")
|
||||
db.exec("create table User (id integer primary key, age int default 0, name text default '');")
|
||||
|
||||
name := 'sam'
|
||||
name := 'Peter'
|
||||
|
||||
db.exec("insert into User (name, age) values ('Sam', 29)")
|
||||
db.exec("insert into User (name, age) values ('Peter', 31)")
|
||||
|
@ -45,10 +45,19 @@ fn test_orm_sqlite() {
|
|||
assert nr_peters == 1
|
||||
println('nr_peters=$nr_peters')
|
||||
//
|
||||
nr_sams := sql db {
|
||||
select count from User where id == 1 && name == name
|
||||
nr_peters2 := sql db {
|
||||
select count from User where id == 2 && name == name
|
||||
}
|
||||
println('nr_sams=$nr_sams')
|
||||
assert nr_peters2 == 1
|
||||
nr_peters3 := sql db {
|
||||
select count from User where name == name
|
||||
}
|
||||
assert nr_peters3 == 1
|
||||
peters := sql db {
|
||||
select from User where name == name // limit 1
|
||||
}
|
||||
assert peters.len == 1
|
||||
assert peters[0].name == 'Peter'
|
||||
//
|
||||
user := sql db {
|
||||
select from User where id == 1
|
||||
|
|
|
@ -356,7 +356,6 @@ pub enum IdentKind {
|
|||
// A single identifier
|
||||
pub struct Ident {
|
||||
pub:
|
||||
value string
|
||||
language table.Language
|
||||
tok_kind token.Kind
|
||||
mod string
|
||||
|
|
|
@ -110,6 +110,7 @@ mut:
|
|||
cur_generic_type table.Type // `int`, `string`, etc in `foo<T>()`
|
||||
sql_i int
|
||||
sql_stmt_name string
|
||||
sql_side SqlExprSide // left or right, to distinguish idents in `name == name`
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -12,6 +12,8 @@ const (
|
|||
dbtype = 'sqlite'
|
||||
)
|
||||
|
||||
enum SqlExprSide { left right }
|
||||
|
||||
fn (mut g Gen) sql_insert_expr(node ast.SqlInsertExpr) {
|
||||
sym := g.table.get_type_symbol(node.table_type)
|
||||
info := sym.info as table.Struct
|
||||
|
@ -135,7 +137,10 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
|||
//
|
||||
g.writeln('int _step_res$tmp = sqlite3_step($g.sql_stmt_name);')
|
||||
if node.is_array {
|
||||
g.writeln('\tprintf("step res=%d\\n", _step_res$tmp);')
|
||||
g.writeln('\tif (_step_res$tmp == SQLITE_DONE) break;')
|
||||
g.writeln('\tif (_step_res$tmp = SQLITE_ROW) ;') // another row
|
||||
g.writeln('\telse if (_step_res$tmp != SQLITE_OK) break;')
|
||||
}
|
||||
for i, field in node.fields {
|
||||
mut func := 'sqlite3_column_int'
|
||||
|
@ -159,6 +164,16 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sql_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) {
|
||||
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) {
|
||||
// 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()
|
||||
|
@ -167,6 +182,7 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
|||
// not a V variable. Need to distinguish column names from V variables.
|
||||
match expr {
|
||||
ast.InfixExpr {
|
||||
g.sql_side = .left
|
||||
g.expr_to_sql(expr.left)
|
||||
match expr.op {
|
||||
.eq { g.write(' = ') }
|
||||
|
@ -178,16 +194,38 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
|||
.logical_or { g.write(' or ') }
|
||||
else {}
|
||||
}
|
||||
g.sql_side = .right
|
||||
g.expr_to_sql(it.right)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
// g.write("'$it.val'")
|
||||
g.inc_sql_i()
|
||||
g.sql_buf.writeln('sqlite3_bind_text($g.sql_stmt_name, $g.sql_i, "$it.val", $it.val.len, 0);')
|
||||
g.sql_bind_string('"$it.val"', it.val.len.str())
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.inc_sql_i()
|
||||
g.sql_buf.writeln('sqlite3_bind_int($g.sql_stmt_name, $g.sql_i, $it.val);')
|
||||
g.sql_bind_int(it.val)
|
||||
}
|
||||
ast.Ident {
|
||||
// `name == user_name` => `name == ?1`
|
||||
// for left sides just add a string, for right sides, generate the bindings
|
||||
if g.sql_side == .left {
|
||||
println("sql gen left $expr.name")
|
||||
g.write(expr.name)
|
||||
} 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)
|
||||
}
|
||||
else {
|
||||
verror('bad sql type $typ')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.expr(expr)
|
||||
|
|
|
@ -55,6 +55,14 @@ fn (mut p Parser) sql_expr() ast.Expr {
|
|||
// return an array
|
||||
typ = table.new_type(p.table.find_or_register_array(table_type, 1, p.mod))
|
||||
}
|
||||
if p.tok.kind ==.name && p.tok.lit == 'limit' {
|
||||
// `limit 1` means that a single object is returned
|
||||
p.check_name() // `limit`
|
||||
if p.tok.kind == .number && p.tok.lit == '1' {
|
||||
query_one = true
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
p.check(.rcbr)
|
||||
// /////////
|
||||
// Register this type's fields as variables so they can be used in `where`
|
||||
|
|
|
@ -30,6 +30,7 @@ pub fn compile_template(html_, fn_name string) string {
|
|||
// lines := os.read_lines(path)
|
||||
mut html := html_.trim_space()
|
||||
mut header := ''
|
||||
mut footer := ''
|
||||
if os.exists('templates/header.html') && html.contains('@header') {
|
||||
h := os.read_file('templates/header.html') or {
|
||||
panic('reading file templates/header.html failed')
|
||||
|
@ -37,6 +38,13 @@ pub fn compile_template(html_, fn_name string) string {
|
|||
header = h.trim_space().replace("\'", '"')
|
||||
html = header + html
|
||||
}
|
||||
if os.exists('templates/footer.html') && html.contains('@footer') {
|
||||
f := os.read_file('templates/footer.html') or {
|
||||
panic('reading file templates/footer.html failed')
|
||||
}
|
||||
footer = f.trim_space().replace("\'", '"')
|
||||
html += footer
|
||||
}
|
||||
|
||||
mut lines := html.split_into_lines()
|
||||
mut s := strings.new_builder(1000)
|
||||
|
@ -48,6 +56,8 @@ fn vweb_tmpl_${fn_name}() {
|
|||
mut sb := strings.new_builder(${lines.len * 30})\n
|
||||
header := \' \' // TODO remove
|
||||
_ = header
|
||||
footer := \' \' // TODO remove
|
||||
_ = footer
|
||||
|
||||
")
|
||||
s.write(str_start)
|
||||
|
|
Loading…
Reference in New Issue