orm: fix select .. limit 1 . This case now returns an ?Row.

pull/1684/head
Delyan Angelov 2019-08-20 15:34:34 +03:00 committed by Alexander Medvednikov
parent 151686501d
commit 49899c649c
3 changed files with 63 additions and 37 deletions

View File

@ -8,6 +8,12 @@ import strings
// `db.select from User where id == 1 && nr_bookings > 0` // `db.select from User where id == 1 && nr_bookings > 0`
fn (p mut Parser) select_query(fn_ph int) string { fn (p mut Parser) select_query(fn_ph int) string {
// NB: qprefix, p.sql_i, p.sql_params SHOULD be reset for each query,
// because we can have many queries in the _same_ scope.
qprefix := p.get_tmp().replace('tmp','sql') + '_'
p.sql_i = 0
p.sql_params = ''
mut q := 'select ' mut q := 'select '
p.check(.key_select) p.check(.key_select)
n := p.check_name() n := p.check_name()
@ -73,36 +79,55 @@ fn (p mut Parser) select_query(fn_ph int) string {
p.is_sql = false p.is_sql = false
limit := p.cgen.end_tmp() limit := p.cgen.end_tmp()
q += ' limit ' + limit q += ' limit ' + limit
// `limit 1` means we are getting `User`, not `[]User` // `limit 1` means we are getting `?User`, not `[]User`
if limit.trim_space() == '1' { if limit.trim_space() == '1' {
query_one = true query_one = true
} }
} }
println('sql query="$q"') println('sql query="$q"')
p.cgen.insert_before('// DEBUG_SQL prefix: $qprefix | fn_ph: $fn_ph | query: "$q" ')
if n == 'count' { if n == 'count' {
p.cgen.set_placeholder(fn_ph, 'pg__DB_q_int(') p.cgen.set_placeholder(fn_ph, 'pg__DB_q_int(')
p.gen(', tos2("$q"))') p.gen(', tos2("$q"))')
} else { } else {
// Build an object, assign each field. // Build an object, assign each field.
tmp := p.get_tmp() tmp := p.get_tmp()
mut obj_gen := strings.new_builder(100) mut obj_gen := strings.new_builder(300)
for i, field in fields { for i, field in fields {
mut cast := '' mut cast := ''
if field.typ == 'int' { if field.typ == 'int' {
cast = 'string_int' cast = 'string_int'
} }
obj_gen.writeln('$tmp . $field.name = $cast( *(string*)array__get(row.vals, $i) );') obj_gen.writeln('${qprefix}$tmp . $field.name = $cast( *(string*)array__get(${qprefix}row.vals, $i) );')
} }
// One object // One object
if query_one { if query_one {
mut params_gen := ''
params := p.sql_params.split(',')
for i, param in params {
params_gen += '${qprefix}params[$i] = int_str($param).str;'
}
p.cgen.insert_before(' p.cgen.insert_before('
pg__Row row = pg__DB_exec_one(db, tos2("$q")); char* ${qprefix}params[$p.sql_i];
$table_name $tmp; $params_gen
Option_${table_name} opt_${qprefix}$tmp;
void* ${qprefix}res = PQexecParams(db.conn, "$q", $p.sql_i, 0, ${qprefix}params, 0, 0, 0) ;
array_pg__Row ${qprefix}rows = pg__res_to_rows ( ${qprefix}res ) ;
Option_pg__Row opt_${qprefix}row = pg__rows_first_or_empty( ${qprefix}rows );
if (! opt_${qprefix}row . ok ) {
opt_${qprefix}$tmp = v_error( opt_${qprefix}row . error );
}else{
$table_name ${qprefix}$tmp;
pg__Row ${qprefix}row = *(pg__Row*) opt_${qprefix}row . data;
${obj_gen.str()} ${obj_gen.str()}
opt_${qprefix}$tmp = opt_ok( & ${qprefix}$tmp, sizeof($table_name) );
}
') ')
p.cgen.resetln(tmp) p.cgen.resetln('opt_${qprefix}$tmp')
} }
// Array // Array
else { else {
@ -110,32 +135,31 @@ ${obj_gen.str()}
mut params_gen := '' mut params_gen := ''
params := p.sql_params.split(',') params := p.sql_params.split(',')
for i, param in params { for i, param in params {
params_gen += 'params[$i] = int_str($param).str;' params_gen += '${qprefix}params[$i] = int_str($param).str;'
} }
p.cgen.insert_before('char* ${qprefix}params[$p.sql_i];
p.cgen.insert_before('char* params[$p.sql_i];
$params_gen $params_gen
void* res = PQexecParams(db.conn, "$q", $p.sql_i, 0, params, 0, 0, 0) ; void* ${qprefix}res = PQexecParams(db.conn, "$q", $p.sql_i, 0, ${qprefix}params, 0, 0, 0) ;
array_pg__Row rows = pg__res_to_rows(res); array_pg__Row ${qprefix}rows = pg__res_to_rows(${qprefix}res);
// TODO preallocate // TODO preallocate
array arr_$tmp = new_array(0, 0, sizeof($table_name)); array ${qprefix}arr_$tmp = new_array(0, 0, sizeof($table_name));
for (int i = 0; i < rows.len; i++) { for (int i = 0; i < ${qprefix}rows.len; i++) {
pg__Row row = *(pg__Row*)array__get(rows, i); pg__Row ${qprefix}row = *(pg__Row*)array__get(${qprefix}rows, i);
$table_name $tmp; $table_name ${qprefix}$tmp;
${obj_gen.str()} ${obj_gen.str()}
_PUSH(&arr_$tmp, $tmp, ${tmp}2, $table_name); _PUSH(&${qprefix}arr_$tmp, ${qprefix}$tmp, ${tmp}2, $table_name);
} }
') ')
p.cgen.resetln('arr_$tmp') p.cgen.resetln('${qprefix}arr_$tmp')
} }
} }
if n == 'count' { if n == 'count' {
return 'int' return 'int'
} else if query_one { } else if query_one {
return table_name return 'Option_$table_name'
} else { } else {
p.register_array('array_$table_name') p.register_array('array_$table_name')
return 'array_$table_name' return 'array_$table_name'

View File

@ -48,7 +48,7 @@ pub fn (nn int) str() string {
return '0' return '0'
} }
max := 16 max := 16
mut buf := malloc(max) mut buf := calloc(max)
mut len := 0 mut len := 0
mut is_neg := false mut is_neg := false
if n < 0 { if n < 0 {

View File

@ -29,6 +29,7 @@ pub:
host string host string
user string user string
password string password string
dbname string
} }
fn C.PQconnectdb(a byteptr) *C.PGconn fn C.PQconnectdb(a byteptr) *C.PGconn
@ -106,21 +107,22 @@ pub fn (db DB) exec(query string) []pg.Row {
return res_to_rows(res) return res_to_rows(res)
} }
pub fn (db DB) exec_one(query string) pg.Row { fn rows_first_or_empty(rows []pg.Row) pg.Row? {
res := C.PQexec(db.conn, query.str)
e := string(C.PQerrorMessage(db.conn))
if e != '' {
println('pg exec error:')
println(e)
return Row{}
}
rows := res_to_rows(res)
if rows.len == 0 { if rows.len == 0 {
return Row{} return error('no row')
} }
return rows[0] return rows[0]
} }
pub fn (db DB) exec_one(query string) pg.Row? {
res := C.PQexec(db.conn, query.str)
e := string(C.PQerrorMessage(db.conn))
if e != '' {
return error('pg exec error: "$e"')
}
row := rows_first_or_empty( res_to_rows(res) )
return row
}
// //
pub fn (db DB) exec_param2(query string, param, param2 string) []pg.Row { pub fn (db DB) exec_param2(query string, param, param2 string) []pg.Row {