Skip to content

Commit db8ff05

Browse files
implement variant_get_json
1 parent a61c48e commit db8ff05

3 files changed

Lines changed: 135 additions & 3 deletions

File tree

src/variant_get.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,25 @@ impl_variant_get_typed!(
296296
|value: Variant<'_, '_>| -> Result<Option<bool>> { Ok(value.as_boolean()) },
297297
);
298298

299+
impl_variant_get_typed!(
300+
/// Extracts a value from a Variant by path and returns it as a JSON string.
301+
///
302+
/// `variant_get_json(variant, path)` returns the value at `path` as a JSON string.
303+
/// - All values are JSON-serialized (strings include quotes, unlike `variant_get_str`)
304+
/// - Returns NULL if the path does not exist
305+
VariantGetJsonUdf,
306+
"variant_get_json",
307+
DataType::Utf8View,
308+
ScalarValue::Utf8View,
309+
|values: Vec<Option<String>>| -> ArrayRef {
310+
let out: StringViewArray = values.into_iter().collect();
311+
Arc::new(out)
312+
},
313+
|value: Variant<'_, '_>| -> Result<Option<String>> {
314+
Ok(Some(value.to_json_string()?))
315+
},
316+
);
317+
299318
#[derive(Debug, Hash, PartialEq, Eq)]
300319
pub struct VariantGetUdf {
301320
signature: Signature,

tests/sqllogictests.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use datafusion::{logical_expr::ScalarUDF, prelude::*};
22
use datafusion_sqllogictest::{DataFusion, TestContext};
33
use datafusion_variant::{
44
CastToVariantUdf, IsVariantNullUdf, JsonToVariantUdf, VariantGetBoolUdf, VariantGetFieldUdf,
5-
VariantGetFloatUdf, VariantGetIntUdf, VariantGetStrUdf, VariantGetUdf, VariantListConstruct,
6-
VariantListDelete, VariantListInsert, VariantObjectConstruct, VariantObjectDelete,
7-
VariantObjectInsert, VariantObjectKeys, VariantPretty, VariantToJsonUdf,
5+
VariantGetFloatUdf, VariantGetIntUdf, VariantGetJsonUdf, VariantGetStrUdf, VariantGetUdf,
6+
VariantListConstruct, VariantListDelete, VariantListInsert, VariantObjectConstruct,
7+
VariantObjectDelete, VariantObjectInsert, VariantObjectKeys, VariantPretty, VariantToJsonUdf,
88
};
99
use indicatif::ProgressBar;
1010
use sqllogictest::strict_column_validator;
@@ -54,6 +54,7 @@ async fn run_sqllogictests() -> Result<(), Box<dyn std::error::Error>> {
5454
ctx.register_udf(ScalarUDF::new_from_impl(VariantGetFloatUdf::default()));
5555
ctx.register_udf(ScalarUDF::new_from_impl(VariantGetIntUdf::default()));
5656
ctx.register_udf(ScalarUDF::new_from_impl(VariantGetBoolUdf::default()));
57+
ctx.register_udf(ScalarUDF::new_from_impl(VariantGetJsonUdf::default()));
5758
ctx.register_udf(ScalarUDF::new_from_impl(VariantGetFieldUdf::default()));
5859
ctx.register_udf(ScalarUDF::new_from_impl(VariantPretty::default()));
5960
ctx.register_udf(ScalarUDF::new_from_impl(VariantObjectConstruct::default()));
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
statement ok
2+
CREATE TABLE json_data (id INT, json_str TEXT) AS VALUES
3+
(1, '{"name": "Alice", "age": 30}'),
4+
(2, '{"name": "Bob", "age": 25}'),
5+
(3, '{"items": [1, 2, 3], "count": 3}'),
6+
(4, 'null'),
7+
(5, '"simple string"'),
8+
(6, '123'),
9+
(7, 'true'),
10+
(8, '{"pi": 3.14, "active": true}');
11+
12+
# string values are returned with json quotes (unlike variant_get_str)
13+
query T
14+
select variant_get_json(json_to_variant(json_str), 'name') from json_data;
15+
----
16+
"Alice"
17+
"Bob"
18+
NULL
19+
NULL
20+
NULL
21+
NULL
22+
NULL
23+
NULL
24+
25+
# integer values are json-serialized
26+
query T
27+
select variant_get_json(json_to_variant(json_str), 'age') from json_data;
28+
----
29+
30
30+
25
31+
NULL
32+
NULL
33+
NULL
34+
NULL
35+
NULL
36+
NULL
37+
38+
# float values are json-serialized
39+
query T
40+
select variant_get_json(json_to_variant(json_str), 'pi') from json_data;
41+
----
42+
NULL
43+
NULL
44+
NULL
45+
NULL
46+
NULL
47+
NULL
48+
NULL
49+
3.14
50+
51+
# boolean values are json-serialized
52+
query T
53+
select variant_get_json(json_to_variant(json_str), 'active') from json_data;
54+
----
55+
NULL
56+
NULL
57+
NULL
58+
NULL
59+
NULL
60+
NULL
61+
NULL
62+
true
63+
64+
# array values are json-serialized
65+
query T
66+
select variant_get_json(json_to_variant(json_str), 'items') from json_data;
67+
----
68+
NULL
69+
NULL
70+
[1,2,3]
71+
NULL
72+
NULL
73+
NULL
74+
NULL
75+
NULL
76+
77+
# missing paths return null
78+
query T
79+
select variant_get_json(json_to_variant(json_str), 'nonexistent') from json_data;
80+
----
81+
NULL
82+
NULL
83+
NULL
84+
NULL
85+
NULL
86+
NULL
87+
NULL
88+
NULL
89+
90+
# scalar variant with nested object
91+
query T
92+
select variant_get_json(json_to_variant('{"obj": {"a": 1}}'), 'obj');
93+
----
94+
{"a":1}
95+
96+
# scalar variant with null value
97+
query T
98+
select variant_get_json(json_to_variant('{"key": null}'), 'key');
99+
----
100+
null
101+
102+
# nested path
103+
query T
104+
select variant_get_json(json_to_variant('{"obj": {"a": "hello"}}'), 'obj.a');
105+
----
106+
"hello"
107+
108+
# nested numeric path
109+
query T
110+
select variant_get_json(json_to_variant('{"obj": {"a": 42}}'), 'obj.a');
111+
----
112+
42

0 commit comments

Comments
 (0)