From 3c12b80abb0096baeeb8a0af26f85c89dd3deaa0 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 29 Jan 2026 23:42:01 +0300 Subject: [PATCH] orm: generic table fixes --- vlib/v/checker/orm.v | 33 ++++++++++++++++--- .../tests/orm_sub_struct_primary_key.out | 7 ++++ .../tests/orm_sub_struct_primary_key.vv | 17 ++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/orm_sub_struct_primary_key.out create mode 100644 vlib/v/checker/tests/orm_sub_struct_primary_key.vv diff --git a/vlib/v/checker/orm.v b/vlib/v/checker/orm.v index 25a042f83..56607ebca 100644 --- a/vlib/v/checker/orm.v +++ b/vlib/v/checker/orm.v @@ -78,6 +78,31 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type { foreign_typ := c.get_field_foreign_table_type(field) + // Get foreign struct's primary key field + foreign_sym := c.table.sym(foreign_typ) + if foreign_sym.info !is ast.Struct { + continue + } + foreign_info := foreign_sym.info as ast.Struct + + // Find primary key field in foreign struct + mut foreign_primary_field := ast.StructField{} + mut foreign_has_primary := false + for f in foreign_info.fields { + if f.attrs.contains('primary') { + foreign_primary_field = f + foreign_has_primary = true + break + } + } + + // Require foreign struct to have a primary key for relationship + if !foreign_has_primary { + c.orm_error('struct `${foreign_sym.name}` used as ORM sub-struct field `${field.name}` must have a `@[primary]` field, or use `@[sql: \'-\']` to skip this field', + field.pos) + continue + } + mut subquery_expr := ast.SqlExpr{ inserted_var: field.name pos: node.pos @@ -105,7 +130,7 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type { scope: c.fn_scope obj: ast.Var{} mod: 'main' - name: 'id' + name: foreign_primary_field.name is_mut: false kind: .unresolved info: ast.IdentVar{} @@ -118,11 +143,11 @@ fn (mut c Checker) sql_expr(mut node ast.SqlExpr) ast.Type { is_mut: false scope: c.fn_scope info: ast.IdentVar{ - typ: ast.int_type + typ: foreign_primary_field.typ } } - left_type: ast.int_type - right_type: ast.int_type + left_type: foreign_primary_field.typ + right_type: foreign_primary_field.typ auto_locked: '' or_block: ast.OrExpr{} } diff --git a/vlib/v/checker/tests/orm_sub_struct_primary_key.out b/vlib/v/checker/tests/orm_sub_struct_primary_key.out new file mode 100644 index 000000000..fea0555d1 --- /dev/null +++ b/vlib/v/checker/tests/orm_sub_struct_primary_key.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/orm_sub_struct_primary_key.vv:9:2: error: ORM: struct `Payload` used as ORM sub-struct field `payload` must have a `@[primary]` field, or use `@[sql: '-']` to skip this field + 7 | struct Message { + 8 | id int @[primary; sql: serial] + 9 | payload Payload + | ~~~~~~~~~~~~~~~ + 10 | } + 11 | diff --git a/vlib/v/checker/tests/orm_sub_struct_primary_key.vv b/vlib/v/checker/tests/orm_sub_struct_primary_key.vv new file mode 100644 index 000000000..b0beffaa4 --- /dev/null +++ b/vlib/v/checker/tests/orm_sub_struct_primary_key.vv @@ -0,0 +1,17 @@ +import db.sqlite + +struct Payload { + data string +} + +struct Message { + id int @[primary; sql: serial] + payload Payload +} + +fn main() { + db := sqlite.connect(':memory:')! + _ := sql db { + select from Message + }! +} -- 2.39.5