Skip to content

Commit

Permalink
orm: add support for V enum struct fields (#19374)
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper64 committed Sep 18, 2023
1 parent e1a48d6 commit 74d80a5
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 2 deletions.
4 changes: 4 additions & 0 deletions cmd/tools/vtest-self.v
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ const (
'vlib/db/sqlite/sqlite_test.v',
'vlib/db/sqlite/sqlite_orm_test.v',
'vlib/db/sqlite/sqlite_vfs_lowlevel_test.v',
'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_joined_tables_select_test.v',
Expand All @@ -165,6 +166,7 @@ const (
'vlib/orm/orm_insert_reserved_name_test.v',
'vlib/orm/orm_references_test.v',
'vlib/v/tests/websocket_logger_interface_should_compile_test.v',
'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
]
Expand All @@ -174,6 +176,7 @@ const (
'vlib/orm/orm_insert_test.v',
'vlib/orm/orm_insert_reserved_name_test.v',
'vlib/orm/orm_references_test.v',
'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v', // fails compilation with: undefined reference to vtable for __cxxabiv1::__function_type_info'
Expand Down Expand Up @@ -219,6 +222,7 @@ const (
'vlib/orm/orm_custom_operators_test.v',
'vlib/orm/orm_fk_test.v',
'vlib/orm/orm_references_test.v',
'vlib/v/tests/orm_enum_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_joined_tables_select_test.v',
Expand Down
3 changes: 3 additions & 0 deletions vlib/orm/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ pub:
is_time bool
default_val string
is_arr bool
is_enum bool
attrs []StructAttribute
}

Expand Down Expand Up @@ -608,6 +609,8 @@ fn sql_field_type(field TableField) int {
mut typ := field.typ
if field.is_time {
return -2
} else if field.is_enum {
return typeof[i64]().idx
}
for attr in field.attrs {
if attr.kind == .plain && attr.name == 'sql' && attr.arg != '' {
Expand Down
11 changes: 9 additions & 2 deletions vlib/v/checker/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,13 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
}

if node.kind == .update {
for mut expr in node.update_exprs {
for i, mut expr in node.update_exprs {
// set enum_col = .enum_val
if mut expr is ast.EnumVal {
column := node.updated_columns[i]
field := node.fields.filter(it.name == column)[0]
c.expected_type = field.typ
}
c.expr(mut expr)
}
}
Expand Down Expand Up @@ -384,6 +390,7 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, t
fsym := c.table.sym(field.typ)
is_struct := fsym.kind == .struct_
is_array := fsym.kind == .array
is_enum := fsym.kind == .enum_
elem_sym := if is_array {
c.table.sym(fsym.array_info().elem_type)
} else {
Expand All @@ -394,7 +401,7 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, t
if has_skip_attr {
continue
}
if is_primitive || is_struct || is_array_with_struct_elements {
if is_primitive || is_struct || is_enum || is_array_with_struct_elements {
fields << field
}
if is_array && elem_sym.is_primitive() {
Expand Down
17 changes: 17 additions & 0 deletions vlib/v/gen/c/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ fn (mut g Gen) write_orm_create_table(node ast.SqlStmtLine, table_name string, c
}
g.writeln('.typ = ${typ}, // `${sym.name}`')
g.writeln('.is_arr = ${sym.kind == .array}, ')
g.writeln('.is_enum = ${sym.kind == .enum_}, ')
g.writeln('.is_time = ${g.table.get_type_name(field.typ) == 'time__Time'},')
g.writeln('.default_val = (string){ .str = (byteptr) "${field.default_val}", .is_lit = 1 },')
g.writeln('.attrs = new_array_from_c_array(${field.attrs.len}, ${field.attrs.len}, sizeof(StructAttribute),')
Expand Down Expand Up @@ -368,6 +369,9 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
g.write('(*(orm__Primitive*) array_get(${last_ids_arr}, ${structs})),')
structs++
continue
} else if sym.kind == .enum_ {
g.write('orm__i64_to_primitive(${node.object_var_name}${member_access_type}${c_name(field.name)}), ')
continue
}
if typ == 'time__Time' {
typ = 'time'
Expand Down Expand Up @@ -458,6 +462,9 @@ fn (mut g Gen) write_orm_expr_to_primitive(expr ast.Expr) {
ast.BoolLiteral {
g.write_orm_primitive(ast.bool_type, expr)
}
ast.EnumVal {
g.write_orm_primitive(ast.i64_type, expr)
}
ast.Ident {
info := expr.info as ast.IdentVar
g.write_orm_primitive(info.typ, expr)
Expand Down Expand Up @@ -699,6 +706,9 @@ fn (mut g Gen) write_orm_where_expr(expr ast.Expr, mut fields []string, mut pare
ast.BoolLiteral {
data << expr
}
ast.EnumVal {
data << expr
}
ast.CallExpr {
data << expr
}
Expand Down Expand Up @@ -775,6 +785,9 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, le
if sym.kind == .struct_ {
types << int(ast.int_type)
continue
} else if sym.kind == .enum_ {
types << int(ast.i64_type)
continue
}
types << int(field.typ)
}
Expand Down Expand Up @@ -979,6 +992,10 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, le

g.write_orm_select(sql_expr_select_array, connection_var_name, '${tmp}.${c_name(field.name)} = ',
or_expr)
} else if sym.kind == .enum_ {
mut typ := sym.cname
g.writeln('${tmp}.${c_name(field.name)} = (${typ}) (*(${array_get_call_code}._i64));')
selected_fields_idx++
} else {
mut typ := sym.cname
g.writeln('${tmp}.${c_name(field.name)} = *(${array_get_call_code}._${typ});')
Expand Down
45 changes: 45 additions & 0 deletions vlib/v/tests/orm_enum_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import db.sqlite

enum Number {
zero
one
two
four = 4
five
}

struct Counter {
id int [primary; sql: serial]
number Number
}

fn test_orm_enum() {
db := sqlite.connect(':memory:') or { panic(err) }
sql db {
create table Counter
}!

counter1 := Counter{
number: .two
}
sql db {
insert counter1 into Counter
}!

mut counters := sql db {
select from Counter
}!

assert counters.first().number == counter1.number

// test short enum syntax
sql db {
update Counter set number = .five where number == .two
}!

counters = sql db {
select from Counter
}!

assert counters.first().number == .five
}

0 comments on commit 74d80a5

Please sign in to comment.