Skip to content

Commit

Permalink
orm: fix multi substructs (#9941)
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisSchmieder committed May 4, 2021
1 parent 92a22e9 commit b8e070b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 17 deletions.
2 changes: 2 additions & 0 deletions cmd/tools/vtest-self.v
Expand Up @@ -20,6 +20,7 @@ const (
'vlib/orm/orm_test.v',
'vlib/sqlite/sqlite_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/vweb/request_test.v',
'vlib/vweb/route_test.v',
Expand Down Expand Up @@ -56,6 +57,7 @@ const (
'vlib/sqlite/sqlite_test.v',
'vlib/orm/orm_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/clipboard/clipboard_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/vweb/request_test.v',
Expand Down
12 changes: 6 additions & 6 deletions examples/database/orm.v
Expand Up @@ -19,9 +19,9 @@ struct User {
}

struct Parent {
id int [primary; sql: serial]
name string
chields []Chield [fkey: 'parent_id']
id int [primary; sql: serial]
name string
children []Chield [fkey: 'parent_id']
}

struct Chield {
Expand All @@ -48,7 +48,7 @@ fn sqlite3_array() {

par := Parent{
name: 'test'
chields: [
children: [
Chield{
name: 'abc'
},
Expand Down Expand Up @@ -90,7 +90,7 @@ fn mysql_array() {

par := Parent{
name: 'test'
chields: [
children: [
Chield{
name: 'abc'
},
Expand Down Expand Up @@ -129,7 +129,7 @@ fn psql_array() {

par := Parent{
name: 'test'
chields: [
children: [
Chield{
name: 'abc'
},
Expand Down
6 changes: 5 additions & 1 deletion vlib/v/checker/checker.v
Expand Up @@ -6708,14 +6708,18 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
} else {
ast.Type(0)
}
mut object_var_name := '${node.object_var_name}.$f.name'
if typ != f.typ {
object_var_name = node.object_var_name
}
mut n := ast.SqlStmtLine{
pos: node.pos
kind: node.kind
table_expr: ast.TypeNode{
pos: node.table_expr.pos
typ: typ
}
object_var_name: '${node.object_var_name}.$f.name'
object_var_name: object_var_name
}
tmp_inside_sql := c.inside_sql
c.sql_stmt_line(mut n)
Expand Down
36 changes: 26 additions & 10 deletions vlib/v/gen/c/sql.v
Expand Up @@ -159,6 +159,7 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)
g.writeln(');')
mut arr_stmt := []ast.SqlStmtLine{}
mut arr_fkeys := []string{}
mut arr_field_name := []string{}
if node.kind == .insert {
// build the object now (`x.name = ... x.id == ...`)
for i, field in node.fields {
Expand Down Expand Up @@ -203,6 +204,7 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)

arr_stmt << node.sub_structs[int(t)]
arr_fkeys << fkey
arr_field_name << field.name
}
} else {
g.writeln('sqlite3_bind_int($g.sql_stmt_name, ${i + 0} , $x); // stmt')
Expand All @@ -224,7 +226,7 @@ fn (mut g Gen) sqlite3_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr)
id_name := g.new_tmp_var()
g.writeln('int $id_name = string_int((*(string*)array_get((*(sqlite__Row*)array_get($res, 0)).vals, 0)));')

g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
g.sql_arr_stmt(arr_stmt, arr_fkeys, arr_field_name, id_name, db_expr)
}
}

Expand Down Expand Up @@ -449,6 +451,7 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('memset($bind, 0, sizeof(MYSQL_BIND)*$g.sql_i);')
mut arr_stmt := []ast.SqlStmtLine{}
mut arr_fkeys := []string{}
mut arr_field_name := []string{}
if node.kind == .insert {
for i, field in node.fields {
if g.get_sql_field_type(field) == ast.Type(-1) {
Expand Down Expand Up @@ -510,6 +513,7 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {

arr_stmt << node.sub_structs[int(t)]
arr_fkeys << fkey
arr_field_name << field.name
}
} else {
t, sym := g.mysql_buffer_typ_from_field(field)
Expand Down Expand Up @@ -549,7 +553,7 @@ fn (mut g Gen) mysql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('int $id_name = string_int(tos_clone(${rs}_row[0]));')
g.writeln('mysql_free_result($rs);')

g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
g.sql_arr_stmt(arr_stmt, arr_fkeys, arr_field_name, id_name, db_expr)
}
}

Expand Down Expand Up @@ -826,6 +830,7 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {

mut arr_stmt := []ast.SqlStmtLine{}
mut arr_fkeys := []string{}
mut arr_field_name := []string{}
if node.kind == .insert {
for i, field in node.fields {
if g.get_sql_field_type(field) == ast.Type(-1) {
Expand Down Expand Up @@ -874,6 +879,7 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {

arr_stmt << node.sub_structs[int(t)]
arr_fkeys << fkey
arr_field_name << field.name
}
} else {
g.sql_buf = strings.new_builder(100)
Expand All @@ -894,8 +900,7 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }')
id_name := g.new_tmp_var()
g.writeln('int $id_name = string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)));')

g.sql_arr_stmt(arr_stmt, arr_fkeys, id_name, db_expr)
g.sql_arr_stmt(arr_stmt, arr_fkeys, arr_field_name, id_name, db_expr)
}
}

Expand Down Expand Up @@ -1162,23 +1167,34 @@ fn (mut g Gen) sql_select_arr(field ast.StructField, node ast.SqlExpr, primary s
}
}

fn (mut g Gen) sql_arr_stmt(arr_stmt []ast.SqlStmtLine, arr_fkeys []string, id_name string, db_expr ast.Expr) {
fn (mut g Gen) sql_arr_stmt(arr_stmt []ast.SqlStmtLine, arr_fkeys []string, arr_field_name []string, id_name string, db_expr ast.Expr) {
for i, s in arr_stmt {
cnt := g.new_tmp_var()
g.writeln('for (int $cnt = 0; $cnt < ${s.object_var_name}.len; $cnt++) {')
g.writeln('for (int $cnt = 0; $cnt < ${s.object_var_name}.${arr_field_name[i]}.len; $cnt++) {')
name := g.table.get_type_symbol(s.table_expr.typ).cname
tmp_var := g.new_tmp_var()
g.writeln('\t$name $tmp_var = (*($name*)array_get($s.object_var_name, $cnt));')

g.writeln('\t$name $tmp_var = (*($name*)array_get(${s.object_var_name}.${arr_field_name[i]}, $cnt));')

mut sub_structs := map[int]ast.SqlStmtLine{}

for key, sub in s.sub_structs {
sub_structs[key] = ast.SqlStmtLine{
pos: sub.pos
kind: sub.kind
table_expr: sub.table_expr
object_var_name: tmp_var
fields: sub.fields
sub_structs: sub.sub_structs
}
}
stmt := ast.SqlStmtLine{
pos: s.pos
kind: s.kind
table_expr: s.table_expr
object_var_name: tmp_var
fields: s.fields
sub_structs: s.sub_structs
sub_structs: sub_structs
}

tmp_fkey := g.sql_fkey
tmp_parent_id := g.sql_parent_id
g.sql_fkey = arr_fkeys[i]
Expand Down
50 changes: 50 additions & 0 deletions vlib/v/tests/orm_sub_array_struct_test.v
@@ -0,0 +1,50 @@
import sqlite

struct Parent {
id int [primary; sql: serial]
name string
chields []Chield [fkey: 'parent_id']
}

struct Chield {
id int [primary; sql: serial]
parent_id int
name string
}

fn test_orm_array() {
mut db := sqlite.connect(':memory:') or { panic(err) }
sql db {
create table Parent
}

par := Parent{
name: 'test'
chields: [
Chield{
name: 'abc'
},
Chield{
name: 'def'
},
]
}

sql db {
insert par into Parent
}

parent := sql db {
select from Parent where id == 1
}

sql db {
drop table Chield
drop table Parent
}

assert parent.name == par.name
assert parent.chields.len == par.chields.len
assert parent.chields[0].name == 'abc'
assert parent.chields[1].name == 'def'
}

0 comments on commit b8e070b

Please sign in to comment.