orm: fix subquery without where expr (#21598)

This commit is contained in:
Felipe Pena 2024-06-04 07:22:06 -03:00 committed by GitHub
parent a2ce55d922
commit 1e86e06eb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 133 additions and 45 deletions

View file

@ -167,6 +167,7 @@ const skip_with_fsanitize_memory = [
'vlib/orm/orm_option_time_test.v', 'vlib/orm/orm_option_time_test.v',
'vlib/db/sqlite/sqlite_test.v', 'vlib/db/sqlite/sqlite_test.v',
'vlib/db/sqlite/sqlite_orm_test.v', 'vlib/db/sqlite/sqlite_orm_test.v',
'vlib/db/sqlite/parent_child_test.v',
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v', 'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
'vlib/v/tests/orm_enum_test.v', 'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_struct_test.v', 'vlib/v/tests/orm_sub_struct_test.v',
@ -238,6 +239,7 @@ const skip_on_ubuntu_musl = [
'vlib/db/sqlite/sqlite_test.v', 'vlib/db/sqlite/sqlite_test.v',
'vlib/db/sqlite/sqlite_orm_test.v', 'vlib/db/sqlite/sqlite_orm_test.v',
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v', 'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
'vlib/db/sqlite/parent_child_test.v',
'vlib/orm/orm_test.v', 'vlib/orm/orm_test.v',
'vlib/orm/orm_sql_or_blocks_test.v', 'vlib/orm/orm_sql_or_blocks_test.v',
'vlib/orm/orm_create_and_drop_test.v', 'vlib/orm/orm_create_and_drop_test.v',

View file

@ -0,0 +1,83 @@
import db.sqlite
struct Parent {
id int @[primary; sql: serial]
name string
children []Child @[fkey: 'parent_id']
}
struct Child {
id int @[primary; sql: serial]
name string
parent_id int
babies []Baby @[fkey: 'child_id']
}
struct Baby {
id int @[primary; sql: serial]
name string
child_id int
}
fn test_main() {
db := sqlite.connect(':memory:')!
sql db {
create table Parent
create table Child
create table Baby
} or { panic(err) }
new_parent := Parent{
name: 'first parent'
children: [
Child{
name: 'first child'
},
Child{
name: 'second_child'
},
]
}
sql db {
insert new_parent into Parent
} or { panic(err) }
babies := [
Baby{
name: 'first baby'
child_id: 1
},
Baby{
name: 'second baby'
child_id: 1
},
Baby{
name: 'third baby'
child_id: 2
},
Baby{
name: 'fourth baby'
child_id: 2
},
Baby{
name: 'fifth baby'
child_id: 2
},
]
for v in babies {
sql db {
insert v into Baby
} or { panic(err) }
}
parent := sql db {
select from Parent
} or { panic(err) }
assert parent[0].children[0].id == 1
assert parent[0].children[1].id == 2
assert parent[0].children.len == 2
}

View file

@ -1068,53 +1068,56 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, re
verror('missing fkey attribute') verror('missing fkey attribute')
} }
sub := node.sub_structs[field.typ] sub := node.sub_structs[field.typ]
mut where_expr := sub.where_expr as ast.InfixExpr if sub.has_where {
mut left_where_expr := where_expr.left as ast.Ident mut where_expr := sub.where_expr as ast.InfixExpr
mut right_where_expr := where_expr.right as ast.Ident mut left_where_expr := where_expr.left as ast.Ident
left_where_expr.name = fkey mut right_where_expr := where_expr.right as ast.Ident
right_where_expr.name = tmp left_where_expr.name = fkey
where_expr.left = left_where_expr right_where_expr.name = tmp
where_expr.right = ast.SelectorExpr{ where_expr.left = left_where_expr
pos: right_where_expr.pos where_expr.right = ast.SelectorExpr{
field_name: primary_field.name pos: right_where_expr.pos
is_mut: false field_name: primary_field.name
expr: right_where_expr is_mut: false
expr_type: (right_where_expr.info as ast.IdentVar).typ expr: right_where_expr
typ: (right_where_expr.info as ast.IdentVar).typ expr_type: (right_where_expr.info as ast.IdentVar).typ
scope: unsafe { nil } typ: (right_where_expr.info as ast.IdentVar).typ
} scope: unsafe { nil }
mut sql_expr_select_array := ast.SqlExpr{ }
typ: field.typ.set_flag(.result)
is_count: sub.is_count
db_expr: sub.db_expr
has_where: sub.has_where
has_offset: sub.has_offset
offset_expr: sub.offset_expr
has_order: sub.has_order
order_expr: sub.order_expr
has_desc: sub.has_desc
is_array: true
is_generated: true
pos: sub.pos
has_limit: sub.has_limit
limit_expr: sub.limit_expr
table_expr: sub.table_expr
fields: sub.fields
where_expr: where_expr
}
sub_result_var := g.new_tmp_var() mut sql_expr_select_array := ast.SqlExpr{
sub_result_c_typ := g.typ(sub.typ) typ: field.typ.set_flag(.result)
g.writeln('${sub_result_c_typ} ${sub_result_var};') is_count: sub.is_count
g.write_orm_select(sql_expr_select_array, connection_var_name, sub_result_var) db_expr: sub.db_expr
g.writeln('if (!${sub_result_var}.is_error) {') has_where: sub.has_where
if field.typ.has_flag(.option) { has_offset: sub.has_offset
g.writeln('\t${field_var}.state = 0;') offset_expr: sub.offset_expr
g.writeln('\t*(${g.base_type(field.typ)}*)${field_var}.data = *(${g.base_type(field.typ)}*)${sub_result_var}.data;') has_order: sub.has_order
} else { order_expr: sub.order_expr
g.writeln('\t${field_var} = *(${unwrapped_c_typ}*)${sub_result_var}.data;') has_desc: sub.has_desc
is_array: true
is_generated: true
pos: sub.pos
has_limit: sub.has_limit
limit_expr: sub.limit_expr
table_expr: sub.table_expr
fields: sub.fields
where_expr: where_expr
}
sub_result_var := g.new_tmp_var()
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) {')
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('}')
} }
g.writeln('}')
} else if field.typ.has_flag(.option) { } else if field.typ.has_flag(.option) {
prim_var := g.new_tmp_var() prim_var := g.new_tmp_var()
g.writeln('orm__Primitive *${prim_var} = &${array_get_call_code};') g.writeln('orm__Primitive *${prim_var} = &${array_get_call_code};')