refactor: Improve struct decoding and skip logic

- Refine `decode_struct` to handle data parsing and error messages
- Enhance `should_skip_field_decode` to cover more skip attribute variations
- Update constants and tests related to struct names
- Adjust `decode_value` to better handle optional types and existing keys
- Modify `decode_struct` to skip optional fields during decoding
This commit is contained in:
Mahmoud-Emad
2025-10-12 16:35:10 +03:00
parent b36bb87513
commit ca95464115
10 changed files with 88 additions and 436 deletions

View File

@@ -13,25 +13,31 @@ pub fn (params Params) decode[T](args T) !T {
pub fn (params Params) decode_struct[T](start T) !T {
mut t := T{}
$for field in T.fields {
// Check if field has skip attribute
mut should_skip := false
for attr in field.attrs {
attr_clean := attr.to_lower()
if attr_clean.contains('skip') {
attr_clean := attr.to_lower().replace(' ', '').replace('\t', '')
if attr_clean == 'skip' || attr_clean.starts_with('skip;')
|| attr_clean.ends_with(';skip') || attr_clean.contains(';skip;') {
should_skip = true
break
}
// Also check for skipdecode
if attr_clean == 'skipdecode' || attr_clean.contains('skipdecode') {
should_skip = true
break
}
}
// println('Field: ${field.name}, should_skip: ${should_skip}, attrs: ${field.attrs}')
if ! should_skip {
if !should_skip {
$if field.is_enum {
t.$(field.name) = params.get_int(field.name) or { int(t.$(field.name)) }
} $else {
// super annoying didn't find other way, then to ignore options
$if field.is_option {
// For optional fields, if the key exists, decode it. Otherwise, leave it as none.
if params.exists(field.name) {
t.$(field.name) = params.decode_value(t.$(field.name), field.name)!
}
// For optional fields, skip decoding entirely
// They will remain as none (default value)
// This avoids type system issues with ?T vs !T
} $else {
if field.name[0].is_capital() {
t.$(field.name) = params.decode_struct(t.$(field.name))!
@@ -46,13 +52,16 @@ pub fn (params Params) decode_struct[T](start T) !T {
}
pub fn (params Params) decode_value[T](val T, key string) !T {
$if T is $option {
return error("is option")
}
// TODO: handle required fields
if !params.exists(key) {
return val // For optional types, this will be `none`. For non-optional, it's the default value.
$if T is $option {
// For optional types, we need to return the value as-is
// This is a workaround for V's type system limitation
// where ?T cannot be directly returned from !T function
mut result := val
return result
}
return val
}
$if T is string {
@@ -89,10 +98,15 @@ pub fn (params Params) decode_value[T](val T, key string) !T {
child_params := params.get_params(key)!
child := child_params.decode_struct(T{})!
return child
} $else $if T is $option {
// For optional types that don't match above patterns
// Return the default value (none)
mut result := val
return result
} $else {
// For any other type, return the default
return val
}
// If no specific decode path is found, return the default value for T.
// For optional types, this will be `none`.
return T{}
}
pub fn (params Params) get_list_bool(key string) ![]bool {
@@ -131,18 +145,7 @@ pub fn encode[T](t T, args EncodeArgs) !Params {
}
}
// // Additional check: if field name suggests it should be skipped
// // This is a fallback for cases where attribute parsing differs
// if field.name == 'other' && !should_skip {
// // Check if any attribute contains 'skip' in any form
// for attr in field.attrs {
// if attr.contains('skip') {
// should_skip = true
// break
// }
// }
// }
<<<<<<< Updated upstream
if !should_skip {
val := t.$(field.name)
field_attrs := attrs_get(field.attrs)