Skip to content

Commit 5d3a619

Browse files
larponpull[bot]
authored andcommitted
toml: streamline value() api (#12568)
1 parent e814ea0 commit 5d3a619

3 files changed

Lines changed: 121 additions & 30 deletions

File tree

vlib/toml/any.v

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,21 @@ pub fn (a Any) default_to(value Any) Any {
163163
}
164164

165165
// value queries a value from the map.
166-
// `key` should be in "dotted" form (`a.b.c`).
167-
// `key` supports quoted keys like `a."b.c"`.
166+
// `key` supports a small query syntax scheme:
167+
// Maps can be queried in "dotted" form e.g. `a.b.c`.
168+
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
169+
// Arrays can be queried with `a[0].b[1].[2]`.
168170
pub fn (m map[string]Any) value(key string) Any {
169-
key_split := parse_dotted_key(key) or { return Any(Null{}) }
170-
return m.value_(key_split)
171+
return Any(m).value(key)
171172
}
172173

173-
fn (m map[string]Any) value_(key []string) Any {
174-
value := m[key[0]] or { return Any(Null{}) }
175-
// `match` isn't currently very suitable for these types of sum type constructs...
176-
if value is map[string]Any {
177-
if key.len <= 1 {
178-
return value
179-
}
180-
nm := (value as map[string]Any)
181-
return nm.value_(key[1..])
182-
}
183-
return value
174+
// value queries a value from the array.
175+
// `key` supports a small query syntax scheme:
176+
// The array can be queried with `[0].b[1].[2]`.
177+
// Maps can be queried in "dotted" form e.g. `a.b.c`.
178+
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
179+
pub fn (a []Any) value(key string) Any {
180+
return Any(a).value(key)
184181
}
185182

186183
pub fn (a []Any) as_strings() []string {
@@ -190,3 +187,42 @@ pub fn (a []Any) as_strings() []string {
190187
}
191188
return sa
192189
}
190+
191+
// value queries a value from the `Any` type.
192+
// `key` supports a small query syntax scheme:
193+
// Maps can be queried in "dotted" form e.g. `a.b.c`.
194+
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
195+
// Arrays can be queried with `a[0].b[1].[2]`.
196+
pub fn (a Any) value(key string) Any {
197+
key_split := parse_dotted_key(key) or { return Any(Null{}) }
198+
return a.value_(a, key_split)
199+
}
200+
201+
// value_ returns the `Any` value found at `key`.
202+
fn (a Any) value_(value Any, key []string) Any {
203+
assert key.len > 0
204+
mut any_value := Any(Null{})
205+
k, index := parse_array_key(key[0])
206+
if k == '' {
207+
arr := value as []Any
208+
any_value = arr[index] or { return Any(Null{}) }
209+
}
210+
if value is map[string]Any {
211+
any_value = value[k] or { return Any(Null{}) }
212+
if index > -1 {
213+
arr := any_value as []Any
214+
any_value = arr[index] or { return Any(Null{}) }
215+
}
216+
}
217+
if key.len <= 1 {
218+
return any_value
219+
}
220+
match any_value {
221+
map[string]Any, []Any {
222+
return a.value_(any_value, key[1..])
223+
}
224+
else {
225+
return value
226+
}
227+
}
228+
}

vlib/toml/tests/value_query_test.v

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ colors = [
1515
"yellow",
1616
[ "transparent" ]
1717
]
18+
19+
[[tests]]
20+
id = 1
21+
22+
[[tests]]
23+
id = 2
24+
25+
[values]
26+
test = 2
27+
28+
[[themes]]
29+
name = "Ice"
30+
colors = [
31+
"blue",
32+
"white"
33+
]
1834
'
1935

2036
fn test_value_query_in_array() {
@@ -29,4 +45,33 @@ fn test_value_query_in_array() {
2945
assert value == 'toml'
3046
value = toml_doc.value('errors[11]').default_to('<none>').string()
3147
assert value == '<none>'
48+
value = toml_doc.value('themes[2].colors[0]').string()
49+
assert value == 'blue'
50+
}
51+
52+
fn test_any_value_query() {
53+
toml_doc := toml.parse(toml_text) or { panic(err) }
54+
themes := toml_doc.value('themes')
55+
assert themes.value('[0].colors[0]').string() == 'red'
56+
57+
themes_arr := toml_doc.value('themes') as []toml.Any
58+
assert themes_arr[0].value('colors[0]').string() == 'red'
59+
60+
mut any := themes
61+
assert any.value('[1].name').string() == 'Lemon'
62+
any = any.value('[1]')
63+
assert any.value('name').string() == 'Lemon'
64+
65+
any = toml_doc.value('themes').value('[1].colors').value('[1]')
66+
assert any.string() == 'yellow'
67+
68+
any = toml_doc.value('themes[1]').value('colors[1]')
69+
assert any.string() == 'yellow'
70+
71+
any = toml_doc.value('themes[1].colors[0]')
72+
assert any.string() == 'green'
73+
74+
any = toml_doc.value('values')
75+
any = any.value('test')
76+
assert any.int() == 2
3277
}

vlib/toml/toml.v

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,21 @@ pub fn parse_dotted_key(key string) ?[]string {
150150
return out
151151
}
152152

153+
// parse_array_key converts `key` string to a key and index part.
154+
fn parse_array_key(key string) (string, int) {
155+
mut index := -1
156+
mut k := key
157+
if k.contains('[') {
158+
index = k.all_after('[').all_before(']').int()
159+
if k.starts_with('[') {
160+
k = '' // k.all_after(']')
161+
} else {
162+
k = k.all_before('[')
163+
}
164+
}
165+
return k, index
166+
}
167+
153168
// to_any converts the `Doc` to toml.Any type.
154169
pub fn (d Doc) to_any() Any {
155170
return d.ast_to_any(d.ast.table)
@@ -159,7 +174,7 @@ pub fn (d Doc) to_any() Any {
159174
// `key` supports a small query syntax scheme:
160175
// Maps can be queried in "dotted" form e.g. `a.b.c`.
161176
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
162-
// Arrays can be queried with `a[0].b[1].[2]`.
177+
// Arrays can be queried with `a[0].b[1].[2]`.
163178
pub fn (d Doc) value(key string) Any {
164179
key_split := parse_dotted_key(key) or { return Any(Null{}) }
165180
return d.value_(d.ast.table, key_split)
@@ -169,16 +184,8 @@ pub fn (d Doc) value(key string) Any {
169184
fn (d Doc) value_(value ast.Value, key []string) Any {
170185
assert key.len > 0
171186
mut ast_value := ast.Value(ast.Null{})
172-
mut index := -1
173-
mut k := key[0]
174-
if k.contains('[') {
175-
index = k.all_after('[').all_before(']').int()
176-
if k.starts_with('[') {
177-
k = '' // k.all_after(']')
178-
} else {
179-
k = k.all_before('[')
180-
}
181-
}
187+
k, index := parse_array_key(key[0])
188+
182189
if k == '' {
183190
a := value as []ast.Value
184191
ast_value = a[index] or { return Any(Null{}) }
@@ -195,11 +202,14 @@ fn (d Doc) value_(value ast.Value, key []string) Any {
195202
if key.len <= 1 {
196203
return d.ast_to_any(ast_value)
197204
}
198-
// `match` isn't currently very suitable for these types of sum type constructs...
199-
if ast_value is map[string]ast.Value || ast_value is []ast.Value {
200-
return d.value_(ast_value, key[1..])
205+
match ast_value {
206+
map[string]ast.Value, []ast.Value {
207+
return d.value_(ast_value, key[1..])
208+
}
209+
else {
210+
return d.ast_to_any(value)
211+
}
201212
}
202-
return d.ast_to_any(value)
203213
}
204214

205215
// ast_to_any converts `from` ast.Value to toml.Any value.

0 commit comments

Comments
 (0)