From f0fb86f76e7de208e3373bc1ace93cb60e2732a8 Mon Sep 17 00:00:00 2001 From: Daniel Daudysh Date: Thu, 29 Jun 2023 06:43:24 +0300 Subject: [PATCH] checker,orm: skip compile-time error msg for fields tagged with `[skip]` and `[sql: '-']` (#18700) --- vlib/orm/orm_test.v | 14 +++++-- vlib/v/ast/attr.v | 4 ++ vlib/v/checker/orm.v | 41 ++++++++++--------- ...ere_clause_unsupported_field_types_err.out | 12 +++--- ...here_clause_unsupported_field_types_err.vv | 4 +- 5 files changed, 44 insertions(+), 31 deletions(-) diff --git a/vlib/orm/orm_test.v b/vlib/orm/orm_test.v index 541a3a5bcc6f15..e36c4a04e65542 100644 --- a/vlib/orm/orm_test.v +++ b/vlib/orm/orm_test.v @@ -18,12 +18,14 @@ struct Module { [table: 'userlist'] struct User { - id int [primary; sql: serial] + id int [primary; sql: serial] age int - name string [sql: 'username'] + name string [sql: 'username'] is_customer bool - skipped_string string [skip] - skipped_string2 string [sql: '-'] + skipped_string string [skip] + skipped_string2 string [sql: '-'] + skipped_array []string [skip] + skipped_array2 []string [sql: '-'] } struct Foo { @@ -50,6 +52,8 @@ fn test_use_struct_field_as_limit() { age: 29 name: 'Sam' skipped_string2: 'this should be ignored' + skipped_array: ['ignored', 'array'] + skipped_array2: ['another', 'ignored', 'array'] } sql db { @@ -65,6 +69,8 @@ fn test_use_struct_field_as_limit() { assert users[0].age == 29 assert users[0].skipped_string == '' assert users[0].skipped_string2 == '' + assert users[0].skipped_array == [], 'skipped because of the [skip] tag, used for both sql and json' + assert users[0].skipped_array2 == [], "should be skipped, because of the sql specific [sql: '-'] tag" } fn test_orm() { diff --git a/vlib/v/ast/attr.v b/vlib/v/ast/attr.v index e29fc5908ca000..eda39d52cfb2d3 100644 --- a/vlib/v/ast/attr.v +++ b/vlib/v/ast/attr.v @@ -54,6 +54,10 @@ pub fn (attrs []Attr) contains(str string) bool { return attrs.any(it.name == str) } +pub fn (attrs []Attr) contains_arg(str string, arg string) bool { + return attrs.any(it.has_arg && it.name == str && it.arg == arg) +} + [direct_array_access] pub fn (attrs []Attr) find_first(aname string) ?Attr { for a in attrs { diff --git a/vlib/v/checker/orm.v b/vlib/v/checker/orm.v index 826c962fcd1fd9..a5cef39b5a7acb 100644 --- a/vlib/v/checker/orm.v +++ b/vlib/v/checker/orm.v @@ -330,26 +330,27 @@ fn (mut c Checker) check_orm_struct_field_attributes(field ast.StructField) { } fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, table_name string, sql_expr ast.SqlExpr) []ast.StructField { - fields := info.fields.filter(fn [mut c] (field ast.StructField) bool { - is_primitive := field.typ.is_string() || field.typ.is_bool() || field.typ.is_number() - is_struct := c.table.type_symbols[int(field.typ)].kind == .struct_ - is_array := c.table.sym(field.typ).kind == .array - is_array_with_struct_elements := is_array - && c.table.sym(c.table.sym(field.typ).array_info().elem_type).kind == .struct_ - has_no_skip_attr := !field.attrs.contains('skip') - - return (is_primitive || is_struct || is_array_with_struct_elements) && has_no_skip_attr - }) - - if fields.len == 0 { - c.orm_error('select: empty fields in `${table_name}`', pos) - return []ast.StructField{} - } - field_pos := c.orm_get_field_pos(sql_expr.where_expr) + mut fields := []ast.StructField{} for field in info.fields { - if c.table.sym(field.typ).kind == .array - && c.table.sym(c.table.sym(field.typ).array_info().elem_type).is_primitive() { + is_primitive := field.typ.is_string() || field.typ.is_bool() || field.typ.is_number() + fsym := c.table.sym(field.typ) + is_struct := fsym.kind == .struct_ + is_array := fsym.kind == .array + elem_sym := if is_array { + c.table.sym(fsym.array_info().elem_type) + } else { + ast.invalid_type_symbol + } + is_array_with_struct_elements := is_array && elem_sym.kind == .struct_ + has_skip_attr := field.attrs.contains('skip') || field.attrs.contains_arg('sql', '-') + if has_skip_attr { + continue + } + if is_primitive || is_struct || is_array_with_struct_elements { + fields << field + } + if is_array && elem_sym.is_primitive() { c.add_error_detail('') c.add_error_detail(' field name: `${field.name}`') c.add_error_detail(' data type: `${c.table.type_to_str(field.typ)}`') @@ -357,7 +358,9 @@ fn (mut c Checker) fetch_and_verify_orm_fields(info ast.Struct, pos token.Pos, t return []ast.StructField{} } } - + if fields.len == 0 { + c.orm_error('select: empty fields in `${table_name}`', pos) + } return fields } diff --git a/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.out b/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.out index f1457596f0aebb..bdd090751427b3 100644 --- a/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.out +++ b/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.out @@ -5,16 +5,16 @@ vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv:15:29: erro | ~~~~~~~ 16 | }! 17 | f := sql db { -Details: +Details: field name: `example` data type: `[]u8` -vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv:18:34: error: V ORM: does not support array of primitive types +vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv:18:30: error: V ORM: does not support array of primitive types 16 | }! 17 | f := sql db { - 18 | select from Example where (example == bytes) - | ~~~~~~~ - 19 | }! + 18 | select from Example where (example == bytes) + | ~~~~~~~ + 19 | }! 20 | print(e) -Details: +Details: field name: `example` data type: `[]u8` diff --git a/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv b/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv index 2ed6d32589c9f2..b2c87f4d8646cb 100644 --- a/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv +++ b/vlib/v/checker/tests/orm_where_clause_unsupported_field_types_err.vv @@ -15,8 +15,8 @@ fn main() { select from Example where example == bytes }! f := sql db { - select from Example where (example == bytes) - }! + select from Example where (example == bytes) + }! print(e) print(f) }