orm: fix code generated for fields of ?[]Type (#20032)

This commit is contained in:
Felipe Pena 2023-11-30 18:36:50 -03:00 committed by GitHub
parent c19b13e165
commit dfab24b936
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 91 additions and 10 deletions

View File

@ -146,6 +146,7 @@ const skip_with_fsanitize_memory = [
'vlib/orm/orm_custom_operators_test.v',
'vlib/orm/orm_fk_test.v',
'vlib/orm/orm_references_test.v',
'vlib/orm/orm_option_array_test.v',
'vlib/orm/orm_option_time_test.v',
'vlib/db/sqlite/sqlite_test.v',
'vlib/db/sqlite/sqlite_orm_test.v',
@ -234,6 +235,7 @@ const skip_on_ubuntu_musl = [
'vlib/orm/orm_custom_operators_test.v',
'vlib/orm/orm_fk_test.v',
'vlib/orm/orm_references_test.v',
'vlib/orm/orm_option_array_test.v',
'vlib/orm/orm_option_time_test.v',
'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_struct_test.v',

View File

@ -0,0 +1,45 @@
import db.sqlite
struct Member {
id int @[primary]
children ?[]Child @[fkey: parent_id]
}
struct Child {
id int @[primary]
parent_id int
}
fn test_main() {
mut db := sqlite.connect(':memory:') or { panic(err) }
defer {
db.close() or { panic(err) }
}
sql db {
create table Member
} or { println(err) }
sql db {
create table Child
} or { println(err) }
new_member := Member{
id: 1
children: [Child{
id: 1
parent_id: 1
}, Child{
id: 2
parent_id: 1
}]
}
sql db {
insert new_member into Member
}!
rows := sql db {
select from Member
}!
assert rows[0].children?.len == 2
assert rows[0].children?[0].id == 1
assert rows[0].children?[1].id == 2
}

View File

@ -276,6 +276,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
mut arrs := []ast.SqlStmtLine{}
mut fkeys := []string{}
mut field_names := []string{}
mut opt_fields := []int{}
for field in node.fields {
sym := g.table.sym(field.typ)
@ -289,6 +290,9 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
} else {
verror('missing fkey attribute')
}
if field.typ.has_flag(.option) {
opt_fields << arrs.len
}
arrs << node.sub_structs[int(field.typ)]
field_names << field.name
}
@ -433,13 +437,22 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
}
for i, mut arr in arrs {
idx := g.new_tmp_var()
g.writeln('for (int ${idx} = 0; ${idx} < ${node.object_var}${member_access_type}${arr.object_var}.len; ${idx}++) {')
ctyp := g.typ(arr.table_expr.typ)
is_option := opt_fields.contains(i)
if is_option {
g.writeln('for (int ${idx} = 0; ${node.object_var}${member_access_type}${arr.object_var}.state != 2 && ${idx} < (*(Array_${ctyp}*)${node.object_var}${member_access_type}${arr.object_var}.data).len; ${idx}++) {')
} else {
g.writeln('for (int ${idx} = 0; ${idx} < ${node.object_var}${member_access_type}${arr.object_var}.len; ${idx}++) {')
}
g.indent++
last_ids := g.new_tmp_var()
res_ := g.new_tmp_var()
tmp_var := g.new_tmp_var()
ctyp := g.typ(arr.table_expr.typ)
g.writeln('${ctyp} ${tmp_var} = (*(${ctyp}*)array_get(${node.object_var}${member_access_type}${arr.object_var}, ${idx}));')
if is_option {
g.writeln('${ctyp} ${tmp_var} = (*(${ctyp}*)array_get(*(Array_${ctyp}*)${node.object_var}${member_access_type}${arr.object_var}.data, ${idx}));')
} else {
g.writeln('${ctyp} ${tmp_var} = (*(${ctyp}*)array_get(${node.object_var}${member_access_type}${arr.object_var}, ${idx}));')
}
arr.object_var = tmp_var
mut fff := []ast.StructField{}
for f in arr.fields {
@ -941,7 +954,13 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re
if node.is_array {
info := g.table.sym(node.typ).array_info()
typ_str = g.typ(info.elem_type)
g.writeln('${unwrapped_c_typ} ${tmp}_array = __new_array(0, ${select_unwrapped_result_var_name}.len, sizeof(${typ_str}));')
base_typ := g.base_type(node.typ)
if node.typ.has_flag(.option) {
g.writeln('${unwrapped_c_typ} ${tmp}_array = { .state = 2, .err = _const_none__, .data = {EMPTY_STRUCT_INITIALIZATION} };')
g.writeln('_option_ok(&(${base_typ}[]) { __new_array(0, ${select_unwrapped_result_var_name}.len, sizeof(${typ_str})) }, (_option *)&${tmp}_array, sizeof(${base_typ}));')
} else {
g.writeln('${unwrapped_c_typ} ${tmp}_array = __new_array(0, ${select_unwrapped_result_var_name}.len, sizeof(${typ_str}));')
}
g.writeln('for (; ${idx} < ${select_unwrapped_result_var_name}.len; ${idx}++) {')
g.indent++
g.write('${typ_str} ${tmp} = (${typ_str}) {')
@ -1053,8 +1072,14 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re
sub_result_c_typ := g.typ(sub.typ)
g.writeln('${sub_result_c_typ} ${sub_result_var};')
g.write_orm_select(sql_expr_select_array, connection_var_name, sub_result_var)
g.writeln('if (!${sub_result_var}.is_error)')
g.writeln('\t${field_var} = *(${unwrapped_c_typ}*)${sub_result_var}.data;')
g.writeln('if (!${sub_result_var}.is_error) {')
if field.typ.has_flag(.option) {
g.writeln('\t${field_var}.state = 0;')
g.writeln('\t*(${g.base_type(field.typ)}*)${field_var}.data = *(${g.base_type(field.typ)}*)${sub_result_var}.data;')
} else {
g.writeln('\t${field_var} = *(${unwrapped_c_typ}*)${sub_result_var}.data;')
}
g.writeln('}')
} else if field.typ.has_flag(.option) {
prim_var := g.new_tmp_var()
g.writeln('orm__Primitive *${prim_var} = &${array_get_call_code};')
@ -1075,7 +1100,12 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re
}
if node.is_array {
g.writeln('array_push(&${tmp}_array, _MOV((${typ_str}[]){ ${tmp} }));')
if node.typ.has_flag(.option) {
g.writeln('${tmp}_array.state = 0;')
g.writeln('array_push((${g.base_type(node.typ)}*)&${tmp}_array.data, _MOV((${typ_str}[]){ ${tmp} }));')
} else {
g.writeln('array_push(&${tmp}_array, _MOV((${typ_str}[]){ ${tmp} }));')
}
g.indent--
g.writeln('}')
}
@ -1083,11 +1113,15 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re
g.indent--
g.writeln('}')
g.write('*(${unwrapped_c_typ}*) ${result_var}.data = ${tmp}')
if node.is_array {
g.write('_array')
if node.typ.has_flag(.option) {
g.writeln('*(${g.base_type(node.typ)}*) ${result_var}.data = *(${g.base_type(node.typ)}*)${tmp}_array.data;')
} else {
g.writeln('*(${unwrapped_c_typ}*) ${result_var}.data = ${tmp}_array;')
}
} else {
g.writeln('*(${unwrapped_c_typ}*) ${result_var}.data = ${tmp};')
}
g.writeln(';')
}
g.indent--