Skip to content

Commit

Permalink
feat: add json_extract_key_value_pairs UDF
Browse files Browse the repository at this point in the history
  • Loading branch information
plaflamme committed May 9, 2024
1 parent 85a0f24 commit 9cf59ac
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
20 changes: 20 additions & 0 deletions udfs/community/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ SELECT bqutil.fn.int(1.684)
* [jaccard](#jaccard)
* [job_url](#job_urljob_id-string)
* [json_extract_keys](#json_extract_keys)
* [json_extract_key_value_pairs](#json_extract_key_value_pairs)
* [json_extract_values](#json_extract_values)
* [json_typeof](#json_typeofjson-string)
* [knots_to_mph](#knots_to_mphinput_knots-float64)
Expand Down Expand Up @@ -1389,6 +1390,25 @@ bar
hat
```

### [json_extract_key_value_pairs()](json_extract_key_value_pairs.sqlx)
Returns all key/values pairs in the input JSON as an array
of STRUCT<key STRING, value STRING>
Returns NULL if invalid JSON string is passed,


```sql
SELECT * FROM UNNEST(
bqutil.fn.json_extract_key_value_pairs(
'{"foo" : "cat", "bar": [1,2,3], "hat": {"qux": true}}'
)
)

key,value
foo,"cat"
bar,[1,2,3]
hat,{"qux":true}
```

### [json_extract_values()](json_extract_values.sqlx)
Returns all values in the input JSON as an array of string
Returns NULL if invalid JSON string is passed,
Expand Down
49 changes: 49 additions & 0 deletions udfs/community/json_extract_key_value_pairs.sqlx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
config { hasOutput: true }
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

CREATE OR REPLACE FUNCTION ${self()}(input STRING)
RETURNS ARRAY<STRUCT<key STRING, value STRING>>
LANGUAGE js
OPTIONS(
description = """Returns all key/values pairs in the input JSON as an array
of STRUCT<key STRING, value STRING>
Returns NULL if invalid JSON string is passed,


```sql
SELECT * FROM UNNEST(
bqutil.fn.json_extract_key_value_pairs(
'{"foo" : "cat", "bar": [1,2,3], "hat": {"qux": true}}'
)
)

key,value
foo,"cat"
bar,[1,2,3]
hat,{"qux":true}
```
"""
)
AS """
try {
return Object.entries(JSON.parse(json_str))
.map(([k, v])=> Object.fromEntries([
["key", k],
["value", JSON.stringify(v)]
]));
} catch {
return null;
}
""";
18 changes: 18 additions & 0 deletions udfs/community/test_cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ generate_udf_test("json_extract_keys", [
expected_output: `cast(null as array<string>)`,
},
]);
generate_udf_test("json_extract_key_value_pairs", [
{
inputs: [`'{"foo" : "cat", "bar": 42, "hat": [1,2,3], "qux": {"bat": true}}'`],
expected_output: `([STRUCT("foo" AS key, "cat" AS value), STRUCT("bar" AS key, "42" AS value), STRUCT("hat" AS key, "[1,2,3]" AS value), STRUCT("qux" AS key, '{"bat":true}' AS value)])`
},
{
inputs: [`'{}'`],
expected_output: `[]`
},
{
inputs: [`'invalid_json'`],
expected_output: `cast(null as array<struct<key string, value string>>)`,
},
{
inputs: [`string(null)`],
expected_output: `cast(null as array<struct<key string, value string>>)`,
},
]);
generate_udf_test("json_extract_values", [
{
inputs: [`'{"foo" : "cat", "bar": "dog", "hat": "rat"}'`],
Expand Down

0 comments on commit 9cf59ac

Please sign in to comment.