orm: support plain @[serial] attribute for marking struct fields (#22814)

This commit is contained in:
Alexander Mandrikov 2024-11-09 22:26:22 +07:00 committed by GitHub
parent f60d285585
commit e1a5acc1ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 81 additions and 3 deletions

View File

@ -166,6 +166,7 @@ const skip_with_fsanitize_memory = [
'vlib/orm/orm_option_array_test.v', 'vlib/orm/orm_option_array_test.v',
'vlib/orm/orm_option_time_test.v', 'vlib/orm/orm_option_time_test.v',
'vlib/orm/orm_order_by_custom_field_test.v', 'vlib/orm/orm_order_by_custom_field_test.v',
'vlib/orm/orm_serial_attribute_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/sqlite_comptime_field_test.v', 'vlib/db/sqlite/sqlite_comptime_field_test.v',
@ -263,6 +264,7 @@ const skip_on_ubuntu_musl = [
'vlib/orm/orm_option_array_test.v', 'vlib/orm/orm_option_array_test.v',
'vlib/orm/orm_option_time_test.v', 'vlib/orm/orm_option_time_test.v',
'vlib/orm/orm_order_by_custom_field_test.v', 'vlib/orm/orm_order_by_custom_field_test.v',
'vlib/orm/orm_serial_attribute_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',
'vlib/v/tests/orm_sub_array_struct_test.v', 'vlib/v/tests/orm_sub_array_struct_test.v',

View File

@ -5205,7 +5205,7 @@ import db.sqlite
// sets a custom table name. Default is struct name (case-sensitive) // sets a custom table name. Default is struct name (case-sensitive)
@[table: 'customers'] @[table: 'customers']
struct Customer { struct Customer {
id int @[primary; sql: serial] // a field named `id` of integer type must be the first field id int @[primary; serial] // a field named `id` of integer type must be the first field
name string name string
nr_orders int nr_orders int
country ?string country ?string

View File

@ -28,7 +28,7 @@ struct Foo {
- `[unique: 'foo']` adds the field to a `UNIQUE` group - `[unique: 'foo']` adds the field to a `UNIQUE` group
- `[skip]` or `[sql: '-']` field will be skipped - `[skip]` or `[sql: '-']` field will be skipped
- `[sql: type]` where `type` is a V type such as `int` or `f64` - `[sql: type]` where `type` is a V type such as `int` or `f64`
- `[sql: serial]` lets the DB backend choose a column type for an auto-increment field - `[serial]` or `[sql: serial]` lets the DB backend choose a column type for an auto-increment field
- `[sql: 'name']` sets a custom column name for the field - `[sql: 'name']` sets a custom column name for the field
- `[sql_type: 'SQL TYPE']` explicitly sets the type in SQL - `[sql_type: 'SQL TYPE']` explicitly sets the type in SQL
- `[default: 'raw_sql']` inserts `raw_sql` verbatim in a "DEFAULT" clause when - `[default: 'raw_sql']` inserts `raw_sql` verbatim in a "DEFAULT" clause when

View File

@ -473,7 +473,7 @@ pub fn orm_table_gen(table string, q string, defaults bool, def_unique_len int,
} }
} }
'primary' { 'primary' {
primary = field.name primary = field_name
primary_typ = field.typ primary_typ = field.typ
} }
'unique' { 'unique' {
@ -592,7 +592,14 @@ pub fn orm_table_gen(table string, q string, defaults bool, def_unique_len int,
fn sql_field_type(field TableField) int { fn sql_field_type(field TableField) int {
mut typ := field.typ mut typ := field.typ
for attr in field.attrs { for attr in field.attrs {
// @[serial]
if attr.name == 'serial' && attr.kind == .plain && !attr.has_arg {
typ = serial
break
}
if attr.kind == .plain && attr.name == 'sql' && attr.arg != '' { if attr.kind == .plain && attr.name == 'sql' && attr.arg != '' {
// @[sql: serial]
if attr.arg.to_lower() == 'serial' { if attr.arg.to_lower() == 'serial' {
typ = serial typ = serial
break break

View File

@ -0,0 +1,67 @@
import db.sqlite
struct PlainNoArg {
id int @[primary; serial; sql: 'custom_id']
name string
}
fn test_plain_no_arg() {
mut db := sqlite.connect(':memory:')!
defer { db.close() or {} }
sql db {
create table PlainNoArg
}!
first := PlainNoArg{
name: 'first'
}
second := PlainNoArg{
name: 'second'
}
sql db {
insert first into PlainNoArg
insert second into PlainNoArg
}!
rows := sql db {
select from PlainNoArg order by id desc
}!
assert rows[0].id == 2
assert rows[0].name == 'second'
}
struct SqlSerial {
id int @[primary; sql: serial]
name string
}
fn test_sql_serial() {
mut db := sqlite.connect(':memory:')!
defer { db.close() or {} }
sql db {
create table SqlSerial
}!
first := SqlSerial{
name: 'first'
}
second := SqlSerial{
name: 'second'
}
sql db {
insert first into SqlSerial
insert second into SqlSerial
}!
rows := sql db {
select from SqlSerial order by id desc
}!
assert rows[0].id == 2
assert rows[0].name == 'second'
}

View File

@ -1274,6 +1274,8 @@ fn get_auto_field_idxs(fields []ast.StructField) []int {
ret << i ret << i
} else if attr.name == 'sql' && attr.arg == 'serial' { } else if attr.name == 'sql' && attr.arg == 'serial' {
ret << i ret << i
} else if attr.name == 'serial' && attr.kind == .plain && !attr.has_arg {
ret << i
} }
} }
} }