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.
// `key` should be in "dotted" form (`a.b.c`).
// `key` supports quoted keys like `a."b.c"`.
// `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 (m map[string]Any) value(key string) Any {
key_split := parse_dotted_key(key) or { return Any(Null{}) }
return m.value_(key_split)
return Any(m).value(key)
}
fn (m map[string]Any) value_(key []string) Any {
value := m[key[0]] or { return Any(Null{}) }
// `match` isn't currently very suitable for these types of sum type constructs...
if value is map[string]Any {
if key.len <= 1 {
return value
}
nm := (value as map[string]Any)
return nm.value_(key[1..])
}
return value
// value queries a value from the array.
// `key` supports a small query syntax scheme:
// The array can be queried with `[0].b[1].[2]`.
// Maps can be queried in "dotted" form e.g. `a.b.c`.
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
pub fn (a []Any) value(key string) Any {
return Any(a).value(key)
}
pub fn (a []Any) as_strings() []string {
@ -190,3 +187,42 @@ pub fn (a []Any) as_strings() []string {
}
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",
[ "transparent" ]
]
[[tests]]
id = 1
[[tests]]
id = 2
[values]
test = 2
[[themes]]
name = "Ice"
colors = [
"blue",
"white"
]
'
fn test_value_query_in_array() {
@ -29,4 +45,33 @@ fn test_value_query_in_array() {
assert value == 'toml'
value = toml_doc.value('errors[11]').default_to('<none>').string()
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
}
// 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.
pub fn (d Doc) to_any() Any {
return d.ast_to_any(d.ast.table)
@ -159,7 +174,7 @@ pub fn (d Doc) to_any() Any {
// `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]`.
// Arrays can be queried with `a[0].b[1].[2]`.
pub fn (d Doc) value(key string) Any {
key_split := parse_dotted_key(key) or { return Any(Null{}) }
return d.value_(d.ast.table, key_split)
@ -169,16 +184,8 @@ pub fn (d Doc) value(key string) Any {
fn (d Doc) value_(value ast.Value, key []string) Any {
assert key.len > 0
mut ast_value := ast.Value(ast.Null{})
mut index := -1
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('[')
}
}
k, index := parse_array_key(key[0])
if k == '' {
a := value as []ast.Value
ast_value = a[index] or { return Any(Null{}) }
@ -195,11 +202,14 @@ fn (d Doc) value_(value ast.Value, key []string) Any {
if key.len <= 1 {
return d.ast_to_any(ast_value)
}
// `match` isn't currently very suitable for these types of sum type constructs...
if ast_value is map[string]ast.Value || ast_value is []ast.Value {
return d.value_(ast_value, key[1..])
match ast_value {
map[string]ast.Value, []ast.Value {
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.