Skip to content

Commit 4446d2b

Browse files
authored
support function unnesting for json_as_text inner calls (#57)
1 parent 6fae049 commit 4446d2b

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

src/rewrite.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,23 @@ fn optimise_json_get_cast(cast: &Cast) -> Option<Transformed<Expr>> {
5252
fn unnest_json_calls(func: &ScalarFunction) -> Option<Transformed<Expr>> {
5353
if !matches!(
5454
func.func.name(),
55-
"json_get" | "json_get_bool" | "json_get_float" | "json_get_int" | "json_get_json" | "json_get_str"
55+
"json_get"
56+
| "json_get_bool"
57+
| "json_get_float"
58+
| "json_get_int"
59+
| "json_get_json"
60+
| "json_get_str"
61+
| "json_as_text"
5662
) {
5763
return None;
5864
}
5965
let mut outer_args_iter = func.args.iter();
6066
let first_arg = outer_args_iter.next()?;
6167
let inner_func = extract_scalar_function(first_arg)?;
62-
if inner_func.func.name() != "json_get" {
68+
69+
// both json_get and json_as_text would produce new JSON to be processed by the outer
70+
// function so can be inlined
71+
if !matches!(inner_func.func.name(), "json_get" | "json_as_text") {
6372
return None;
6473
}
6574

tests/main.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,38 @@ async fn test_plan_arrow_double_nested() {
880880
assert_eq!(lines, expected);
881881
}
882882

883+
#[tokio::test]
884+
async fn test_double_arrow_double_nested() {
885+
let batches = run_query("select name, json_data->>'foo'->>0 from test").await.unwrap();
886+
887+
let expected = [
888+
"+------------------+---------------------------------------------+",
889+
"| name | test.json_data ->> Utf8(\"foo\") ->> Int64(0) |",
890+
"+------------------+---------------------------------------------+",
891+
"| object_foo | |",
892+
"| object_foo_array | 1 |",
893+
"| object_foo_obj | |",
894+
"| object_foo_null | |",
895+
"| object_bar | |",
896+
"| list_foo | |",
897+
"| invalid_json | |",
898+
"+------------------+---------------------------------------------+",
899+
];
900+
assert_batches_eq!(expected, &batches);
901+
}
902+
903+
#[tokio::test]
904+
async fn test_plan_double_arrow_double_nested() {
905+
let lines = logical_plan(r"explain select json_data->>'foo'->>0 from test").await;
906+
907+
let expected = [
908+
"Projection: json_as_text(test.json_data, Utf8(\"foo\"), Int64(0)) AS test.json_data ->> Utf8(\"foo\") ->> Int64(0)",
909+
" TableScan: test projection=[json_data]",
910+
];
911+
912+
assert_eq!(lines, expected);
913+
}
914+
883915
#[tokio::test]
884916
async fn test_arrow_double_nested_cast() {
885917
let batches = run_query("select name, (json_data->'foo'->0)::int from test")
@@ -914,6 +946,41 @@ async fn test_plan_arrow_double_nested_cast() {
914946
assert_eq!(lines, expected);
915947
}
916948

949+
#[tokio::test]
950+
async fn test_double_arrow_double_nested_cast() {
951+
let batches = run_query("select name, (json_data->>'foo'->>0)::int from test")
952+
.await
953+
.unwrap();
954+
955+
let expected = [
956+
"+------------------+---------------------------------------------+",
957+
"| name | test.json_data ->> Utf8(\"foo\") ->> Int64(0) |",
958+
"+------------------+---------------------------------------------+",
959+
"| object_foo | |",
960+
"| object_foo_array | 1 |",
961+
"| object_foo_obj | |",
962+
"| object_foo_null | |",
963+
"| object_bar | |",
964+
"| list_foo | |",
965+
"| invalid_json | |",
966+
"+------------------+---------------------------------------------+",
967+
];
968+
assert_batches_eq!(expected, &batches);
969+
}
970+
971+
#[tokio::test]
972+
async fn test_plan_double_arrow_double_nested_cast() {
973+
let lines = logical_plan(r"explain select (json_data->>'foo'->>0)::int from test").await;
974+
975+
// NB: json_as_text(..)::int is NOT the same as `json_get_int(..)`, hence the cast is not rewritten
976+
let expected = [
977+
"Projection: CAST(json_as_text(test.json_data, Utf8(\"foo\"), Int64(0)) AS test.json_data ->> Utf8(\"foo\") ->> Int64(0) AS Int32)",
978+
" TableScan: test projection=[json_data]",
979+
];
980+
981+
assert_eq!(lines, expected);
982+
}
983+
917984
#[tokio::test]
918985
async fn test_arrow_nested_columns() {
919986
let expected = [

0 commit comments

Comments
 (0)