mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
orm: allow structs without the id field, more flexible primary keys (#18140)
This commit is contained in:
committed by
GitHub
parent
72b2f22057
commit
6ac09e605e
@@ -212,6 +212,7 @@ fn (mut c Checker) sql_stmt_line(mut node ast.SqlStmtLine) ast.Type {
|
||||
info := table_sym.info as ast.Struct
|
||||
mut fields := c.fetch_and_verify_orm_fields(info, node.table_expr.pos, table_sym.name)
|
||||
mut sub_structs := map[int]ast.SqlStmtLine{}
|
||||
|
||||
for f in fields.filter((c.table.type_symbols[int(it.typ)].kind == .struct_
|
||||
|| (c.table.sym(it.typ).kind == .array
|
||||
&& c.table.sym(c.table.sym(it.typ).array_info().elem_type).kind == .struct_))
|
||||
@@ -332,9 +333,7 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, t
|
||||
c.orm_error('select: empty fields in `${table_name}`', pos)
|
||||
return []ast.StructField{}
|
||||
}
|
||||
if fields[0].name != 'id' {
|
||||
c.orm_error('`id int` must be the first field in `${table_name}`', pos)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -537,6 +536,20 @@ fn (mut c Checker) check_db_expr(db_expr &ast.Expr) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// walkingdevel: Now I don't think it's a good solution
|
||||
// because it only checks structure initialization,
|
||||
// but structure fields may be updated later before inserting.
|
||||
// For example,
|
||||
// ```v
|
||||
// mut package := Package{
|
||||
// name: 'xml'
|
||||
// }
|
||||
//
|
||||
// package.author = User{
|
||||
// username: 'walkingdevel'
|
||||
// }
|
||||
// ```
|
||||
// TODO: rewrite it, move to runtime.
|
||||
fn (_ &Checker) check_field_of_inserting_struct_is_uninitialized(node &ast.SqlStmtLine, field_name string) bool {
|
||||
struct_scope := node.scope.find_var(node.object_var_name) or { return false }
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
|
||||
}
|
||||
|
||||
fields := node.fields.filter(g.table.sym(it.typ).kind != .array)
|
||||
primary_field_name := g.get_orm_struct_primary_field_name(fields) or { '' }
|
||||
|
||||
for sub in subs {
|
||||
g.sql_stmt_line(sub, connection_var_name, or_expr)
|
||||
@@ -373,6 +374,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
|
||||
g.indent--
|
||||
g.writeln('),')
|
||||
g.writeln('.types = __new_array_with_default_noscan(0, 0, sizeof(int), 0),')
|
||||
g.writeln('.primary_column_name = _SLIT("${primary_field_name}"),')
|
||||
g.writeln('.kinds = __new_array_with_default_noscan(0, 0, sizeof(orm__OperationKind), 0),')
|
||||
g.writeln('.is_and = __new_array_with_default_noscan(0, 0, sizeof(bool), 0),')
|
||||
g.indent--
|
||||
@@ -396,11 +398,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
|
||||
mut fff := []ast.StructField{}
|
||||
for f in arr.fields {
|
||||
mut skip := false
|
||||
mut primary := false
|
||||
for attr in f.attrs {
|
||||
if attr.name == 'primary' {
|
||||
primary = true
|
||||
}
|
||||
if attr.name == 'skip' {
|
||||
skip = true
|
||||
}
|
||||
@@ -408,7 +406,7 @@ fn (mut g Gen) write_orm_insert_with_last_ids(node ast.SqlStmtLine, connection_v
|
||||
skip = true
|
||||
}
|
||||
}
|
||||
if !skip && !primary {
|
||||
if !skip {
|
||||
fff << f
|
||||
}
|
||||
}
|
||||
@@ -986,19 +984,14 @@ fn (mut g Gen) write_orm_select(node ast.SqlExpr, connection_var_name string, le
|
||||
}
|
||||
|
||||
// filter_struct_fields_by_orm_attrs filters struct fields taking into its attributes.
|
||||
// Used by non-create queries for skipping fields
|
||||
// if it has a `skip` attribute or `primary` that inserts automatically.
|
||||
// Used by non-create queries for skipping fields.
|
||||
fn (_ &Gen) filter_struct_fields_by_orm_attrs(fields []ast.StructField) []ast.StructField {
|
||||
mut result := []ast.StructField{}
|
||||
|
||||
for field in fields {
|
||||
mut skip := false
|
||||
mut primary := false
|
||||
|
||||
for attr in field.attrs {
|
||||
if attr.name == 'primary' {
|
||||
primary = true
|
||||
}
|
||||
if attr.name == 'skip' {
|
||||
skip = true
|
||||
}
|
||||
@@ -1007,7 +1000,7 @@ fn (_ &Gen) filter_struct_fields_by_orm_attrs(fields []ast.StructField) []ast.St
|
||||
}
|
||||
}
|
||||
|
||||
if !skip && !primary {
|
||||
if !skip {
|
||||
result << field
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ fn test_orm_array() {
|
||||
create table Child
|
||||
}!
|
||||
|
||||
par := Parent{
|
||||
new_parent := Parent{
|
||||
name: 'test'
|
||||
children: [
|
||||
Child{
|
||||
@@ -35,7 +35,7 @@ fn test_orm_array() {
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert par into Parent
|
||||
insert new_parent into Parent
|
||||
}!
|
||||
|
||||
parents := sql db {
|
||||
@@ -47,8 +47,8 @@ fn test_orm_array() {
|
||||
}!
|
||||
|
||||
parent := parents.first()
|
||||
assert parent.name == par.name
|
||||
assert parent.children.len == par.children.len
|
||||
assert parent.name == new_parent.name
|
||||
assert parent.children.len == new_parent.children.len
|
||||
assert parent.children[0].name == 'abc'
|
||||
assert parent.children[1].name == 'def'
|
||||
}
|
||||
@@ -57,8 +57,6 @@ fn test_orm_relationship() {
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
sql db {
|
||||
create table Parent
|
||||
}!
|
||||
sql db {
|
||||
create table Child
|
||||
}!
|
||||
|
||||
@@ -66,13 +64,12 @@ fn test_orm_relationship() {
|
||||
name: 'abc'
|
||||
}
|
||||
|
||||
par := Parent{
|
||||
new_parent := Parent{
|
||||
name: 'test'
|
||||
children: []
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert par into Parent
|
||||
insert new_parent into Parent
|
||||
}!
|
||||
|
||||
mut parents := sql db {
|
||||
@@ -93,7 +90,7 @@ fn test_orm_relationship() {
|
||||
insert child into Child
|
||||
}!
|
||||
|
||||
assert parent.name == par.name
|
||||
assert parent.name == new_parent.name
|
||||
assert parent.children.len == 0
|
||||
|
||||
parents = sql db {
|
||||
@@ -101,7 +98,7 @@ fn test_orm_relationship() {
|
||||
}!
|
||||
|
||||
parent = parents.first()
|
||||
assert parent.name == par.name
|
||||
assert parent.name == new_parent.name
|
||||
assert parent.children.len == 2
|
||||
assert parent.children[0].name == 'atum'
|
||||
assert parent.children[1].name == 'bacon'
|
||||
|
||||
Reference in New Issue
Block a user