mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
json: use @[required]
to disallow parsing nulls (#23218)
This commit is contained in:
parent
1ca902fcc4
commit
63fff1dcd4
3 changed files with 64 additions and 11 deletions
|
@ -4692,7 +4692,7 @@ struct User {
|
|||
last_name string @[json: lastName]
|
||||
}
|
||||
|
||||
data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25 }'
|
||||
data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25, "nullable": null }'
|
||||
user := json.decode(User, data) or {
|
||||
eprintln('Failed to decode json, error: ${err}')
|
||||
return
|
||||
|
|
|
@ -516,12 +516,9 @@ fn test_encode_alias_field() {
|
|||
a: 1
|
||||
}
|
||||
})
|
||||
println(s)
|
||||
assert s == '{"sub":{"a":1}}'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
struct APrice {}
|
||||
|
||||
struct Association {
|
||||
|
@ -538,3 +535,55 @@ fn test_encoding_struct_with_pointers() {
|
|||
}
|
||||
assert json.encode(value) == '{"association":{"price":{}},"price":{}}'
|
||||
}
|
||||
|
||||
struct ChildNullish {
|
||||
name string
|
||||
}
|
||||
|
||||
struct NullishStruct {
|
||||
name string
|
||||
lastname string
|
||||
age int
|
||||
salary f32
|
||||
child ChildNullish
|
||||
}
|
||||
|
||||
struct RequiredStruct {
|
||||
name string @[required]
|
||||
lastname string
|
||||
}
|
||||
|
||||
fn test_required() {
|
||||
nullish_one := json.decode(NullishStruct, '{"name":"Peter", "lastname":null, "age":28,"salary":95000.5,"title":"worker"}')!
|
||||
assert nullish_one.name == 'Peter'
|
||||
assert nullish_one.lastname == ''
|
||||
assert nullish_one.age == 28
|
||||
assert nullish_one.salary == 95000.5
|
||||
assert nullish_one.child.name == ''
|
||||
|
||||
nullish_two := json.decode(NullishStruct, '{"name":"Peter", "lastname": "Parker", "age":28,"salary":95000.5,"title":"worker"}')!
|
||||
assert nullish_two.name == 'Peter'
|
||||
assert nullish_two.lastname == 'Parker'
|
||||
assert nullish_two.age == 28
|
||||
assert nullish_two.salary == 95000.5
|
||||
assert nullish_two.child.name == ''
|
||||
|
||||
nullish_third := json.decode(NullishStruct, '{"name":"Peter", "age":28,"salary":95000.5,"title":"worker", "child": {"name":"Nullish"}}')!
|
||||
assert nullish_third.name == 'Peter'
|
||||
assert nullish_third.lastname == ''
|
||||
assert nullish_third.age == 28
|
||||
assert nullish_third.salary == 95000.5
|
||||
assert nullish_third.child.name == 'Nullish'
|
||||
|
||||
required_struct := json.decode(RequiredStruct, '{"name":"Peter", "lastname": "Parker"}')!
|
||||
assert required_struct.name == 'Peter'
|
||||
assert required_struct.lastname == 'Parker'
|
||||
|
||||
required_struct_err := json.decode(RequiredStruct, '{"name": null, "lastname": "Parker"}') or {
|
||||
assert err.msg() == "type mismatch for field 'name', expecting `string` type, got: null"
|
||||
RequiredStruct{
|
||||
name: 'Peter'
|
||||
lastname: 'Parker'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -627,8 +627,12 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_prim_type_validation(name string, typ ast.Type, tmp string, ret_styp string, mut dec strings.Builder) {
|
||||
none_check := if typ.has_flag(.option) { 'cJSON_IsNull(jsonroot_${tmp}) || ' } else { '' }
|
||||
fn (mut g Gen) gen_prim_type_validation(name string, typ ast.Type, tmp string, is_required bool, ret_styp string, mut dec strings.Builder) {
|
||||
none_check := if !is_required {
|
||||
'cJSON_IsNull(jsonroot_${tmp}) || '
|
||||
} else {
|
||||
''
|
||||
}
|
||||
type_check := if typ.is_int() || typ.is_float() {
|
||||
'${none_check}cJSON_IsNumber(jsonroot_${tmp}) || (cJSON_IsString(jsonroot_${tmp}) && strlen(jsonroot_${tmp}->valuestring))'
|
||||
} else if typ.is_string() {
|
||||
|
@ -724,7 +728,7 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st
|
|||
if utyp.has_flag(.option) {
|
||||
dec.writeln('\t\tres.state = 0;')
|
||||
}
|
||||
g.gen_prim_type_validation(field.name, field.typ, tmp, '${result_name}_${styp}', mut
|
||||
g.gen_prim_type_validation(field.name, field.typ, tmp, is_required, '${result_name}_${styp}', mut
|
||||
dec)
|
||||
dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = ${dec_name}(jsonroot_${tmp});')
|
||||
if field.has_default_expr {
|
||||
|
@ -791,8 +795,8 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st
|
|||
tmp := g.new_tmp_var()
|
||||
gen_js_get(styp, tmp, name, mut dec, is_required)
|
||||
dec.writeln('\tif (jsonroot_${tmp}) {')
|
||||
g.gen_prim_type_validation(field.name, parent_type, tmp, '${result_name}_${styp}', mut
|
||||
dec)
|
||||
g.gen_prim_type_validation(field.name, parent_type, tmp, is_required,
|
||||
'${result_name}_${styp}', mut dec)
|
||||
dec.writeln('\t\t${prefix}${op}${c_name(field.name)} = ${parent_dec_name} (jsonroot_${tmp});')
|
||||
if field.has_default_expr {
|
||||
dec.writeln('\t} else {')
|
||||
|
@ -832,8 +836,8 @@ fn (mut g Gen) gen_struct_enc_dec(utyp ast.Type, type_info ast.TypeInfo, styp st
|
|||
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
|
||||
dec.writeln('\tif (jsonroot_${tmp}) {')
|
||||
if is_js_prim(g.styp(field.typ.clear_option_and_result())) {
|
||||
g.gen_prim_type_validation(field.name, field.typ, tmp, '${result_name}_${styp}', mut
|
||||
dec)
|
||||
g.gen_prim_type_validation(field.name, field.typ, tmp, is_required,
|
||||
'${result_name}_${styp}', mut dec)
|
||||
}
|
||||
if field.typ.has_flag(.option) {
|
||||
dec.writeln('\t\tvmemcpy(&${prefix}${op}${c_name(field.name)}, (${field_type}*)${tmp}.data, sizeof(${field_type}));')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue