toml: streamline value() api (#12568)

pull/12571/head
Larpon 2021-11-24 19:39:22 +01:00 committed by GitHub
parent f825306cff
commit 11d70624af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 30 deletions

View File

@ -163,24 +163,21 @@ pub fn (a Any) default_to(value Any) Any {
} }
// value queries a value from the map. // value queries a value from the map.
// `key` should be in "dotted" form (`a.b.c`). // `key` supports a small query syntax scheme:
// `key` supports quoted keys like `a."b.c"`. // Maps can be queried in "dotted" form e.g. `a.b.c`.
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
// Arrays can be queried with `a[0].b[1].[2]`.
pub fn (m map[string]Any) value(key string) Any { pub fn (m map[string]Any) value(key string) Any {
key_split := parse_dotted_key(key) or { return Any(Null{}) } return Any(m).value(key)
return m.value_(key_split)
} }
fn (m map[string]Any) value_(key []string) Any { // value queries a value from the array.
value := m[key[0]] or { return Any(Null{}) } // `key` supports a small query syntax scheme:
// `match` isn't currently very suitable for these types of sum type constructs... // The array can be queried with `[0].b[1].[2]`.
if value is map[string]Any { // Maps can be queried in "dotted" form e.g. `a.b.c`.
if key.len <= 1 { // quoted keys are supported as `a."b.c"` or `a.'b.c'`.
return value pub fn (a []Any) value(key string) Any {
} return Any(a).value(key)
nm := (value as map[string]Any)
return nm.value_(key[1..])
}
return value
} }
pub fn (a []Any) as_strings() []string { pub fn (a []Any) as_strings() []string {
@ -190,3 +187,42 @@ pub fn (a []Any) as_strings() []string {
} }
return sa return sa
} }
// value queries a value from the `Any` type.
// `key` supports a small query syntax scheme:
// Maps can be queried in "dotted" form e.g. `a.b.c`.
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
// Arrays can be queried with `a[0].b[1].[2]`.
pub fn (a Any) value(key string) Any {
key_split := parse_dotted_key(key) or { return Any(Null{}) }
return a.value_(a, key_split)
}
// value_ returns the `Any` value found at `key`.
fn (a Any) value_(value Any, key []string) Any {
assert key.len > 0
mut any_value := Any(Null{})
k, index := parse_array_key(key[0])
if k == '' {
arr := value as []Any
any_value = arr[index] or { return Any(Null{}) }
}
if value is map[string]Any {
any_value = value[k] or { return Any(Null{}) }
if index > -1 {
arr := any_value as []Any
any_value = arr[index] or { return Any(Null{}) }
}
}
if key.len <= 1 {
return any_value
}
match any_value {
map[string]Any, []Any {
return a.value_(any_value, key[1..])
}
else {
return value
}
}
}

View File

@ -15,6 +15,22 @@ colors = [
"yellow", "yellow",
[ "transparent" ] [ "transparent" ]
] ]
[[tests]]
id = 1
[[tests]]
id = 2
[values]
test = 2
[[themes]]
name = "Ice"
colors = [
"blue",
"white"
]
' '
fn test_value_query_in_array() { fn test_value_query_in_array() {
@ -29,4 +45,33 @@ fn test_value_query_in_array() {
assert value == 'toml' assert value == 'toml'
value = toml_doc.value('errors[11]').default_to('<none>').string() value = toml_doc.value('errors[11]').default_to('<none>').string()
assert value == '<none>' assert value == '<none>'
value = toml_doc.value('themes[2].colors[0]').string()
assert value == 'blue'
}
fn test_any_value_query() {
toml_doc := toml.parse(toml_text) or { panic(err) }
themes := toml_doc.value('themes')
assert themes.value('[0].colors[0]').string() == 'red'
themes_arr := toml_doc.value('themes') as []toml.Any
assert themes_arr[0].value('colors[0]').string() == 'red'
mut any := themes
assert any.value('[1].name').string() == 'Lemon'
any = any.value('[1]')
assert any.value('name').string() == 'Lemon'
any = toml_doc.value('themes').value('[1].colors').value('[1]')
assert any.string() == 'yellow'
any = toml_doc.value('themes[1]').value('colors[1]')
assert any.string() == 'yellow'
any = toml_doc.value('themes[1].colors[0]')
assert any.string() == 'green'
any = toml_doc.value('values')
any = any.value('test')
assert any.int() == 2
} }

View File

@ -150,6 +150,21 @@ pub fn parse_dotted_key(key string) ?[]string {
return out return out
} }
// parse_array_key converts `key` string to a key and index part.
fn parse_array_key(key string) (string, int) {
mut index := -1
mut k := key
if k.contains('[') {
index = k.all_after('[').all_before(']').int()
if k.starts_with('[') {
k = '' // k.all_after(']')
} else {
k = k.all_before('[')
}
}
return k, index
}
// to_any converts the `Doc` to toml.Any type. // to_any converts the `Doc` to toml.Any type.
pub fn (d Doc) to_any() Any { pub fn (d Doc) to_any() Any {
return d.ast_to_any(d.ast.table) return d.ast_to_any(d.ast.table)
@ -169,16 +184,8 @@ pub fn (d Doc) value(key string) Any {
fn (d Doc) value_(value ast.Value, key []string) Any { fn (d Doc) value_(value ast.Value, key []string) Any {
assert key.len > 0 assert key.len > 0
mut ast_value := ast.Value(ast.Null{}) mut ast_value := ast.Value(ast.Null{})
mut index := -1 k, index := parse_array_key(key[0])
mut k := key[0]
if k.contains('[') {
index = k.all_after('[').all_before(']').int()
if k.starts_with('[') {
k = '' // k.all_after(']')
} else {
k = k.all_before('[')
}
}
if k == '' { if k == '' {
a := value as []ast.Value a := value as []ast.Value
ast_value = a[index] or { return Any(Null{}) } ast_value = a[index] or { return Any(Null{}) }
@ -195,12 +202,15 @@ fn (d Doc) value_(value ast.Value, key []string) Any {
if key.len <= 1 { if key.len <= 1 {
return d.ast_to_any(ast_value) return d.ast_to_any(ast_value)
} }
// `match` isn't currently very suitable for these types of sum type constructs... match ast_value {
if ast_value is map[string]ast.Value || ast_value is []ast.Value { map[string]ast.Value, []ast.Value {
return d.value_(ast_value, key[1..]) return d.value_(ast_value, key[1..])
} }
else {
return d.ast_to_any(value) return d.ast_to_any(value)
} }
}
}
// ast_to_any converts `from` ast.Value to toml.Any value. // ast_to_any converts `from` ast.Value to toml.Any value.
pub fn (d Doc) ast_to_any(value ast.Value) Any { pub fn (d Doc) ast_to_any(value ast.Value) Any {