Skip to content

Commit 3f2d0fb

Browse files
authored
Add JSON Extract Functions (#270)
1 parent 33aa63a commit 3f2d0fb

File tree

4 files changed

+117
-20
lines changed

4 files changed

+117
-20
lines changed

udfs/community/README.md

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ SELECT bqutil.fn.int(1.684)
2424
* [getbit](#getbittarget_arg-int64-target_bit_arg-int64)
2525
* [get_value](#get_valuek-string-arr-any-type)
2626
* [int](#intv-any-type)
27+
* [json_extract_keys](#json_extract_keys)
28+
* [json_extract_values](#json_extract_values)
2729
* [json_typeof](#json_typeofjson-string)
2830
* [kruskal_wallis](#kruskal_wallisarraystructfactor-string-val-float64)
2931
* [last_day](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#last_day)
@@ -96,11 +98,11 @@ results:
9698
### [day_occurrence_of_month(date_expression ANY TYPE)](day_occurrence_of_month.sqlx)
9799
Returns the nth occurrence of the weekday in the month for the specified date. The result is an INTEGER value between 1 and 5.
98100
```sql
99-
SELECT
100-
bqutil.fn.day_occurrence_of_month(DATE '2020-07-01'),
101+
SELECT
102+
bqutil.fn.day_occurrence_of_month(DATE '2020-07-01'),
101103
bqutil.fn.day_occurrence_of_month(DATE '2020-07-08');
102-
103-
1 2
104+
105+
1 2
104106
```
105107

106108
### [degrees(x ANY TYPE)](degrees.sqlx)
@@ -169,10 +171,10 @@ results:
169171
Returns a number in decimal form from its binary representation.
170172

171173
```sql
172-
SELECT
174+
SELECT
173175
bqutil.fn.to_binary(x) AS binary,
174176
bqutil.fn.from_binary(bqutil.fn.to_binary(x)) AS x
175-
FROM
177+
FROM
176178
UNNEST([1, 123456, 9876543210, -1001]) AS x;
177179
```
178180

@@ -190,10 +192,10 @@ results:
190192
Returns a number in decimal form from its hexadecimal representation.
191193

192194
```sql
193-
SELECT
194-
bqutil.fn.to_hex(x) AS hex,
195+
SELECT
196+
bqutil.fn.to_hex(x) AS hex,
195197
bqutil.fn.from_hex(bqutil.fn.to_hex(x)) AS x
196-
FROM
198+
FROM
197199
UNNEST([1, 123456, 9876543210, -1001]) AS x;
198200
```
199201

@@ -281,6 +283,31 @@ SELECT bqutil.fn.int(1) int1
281283

282284
Note that CAST(x AS INT64) rounds the number, while this function truncates it. In many cases, that's the behavior users expect.
283285

286+
### [json_extract_keys()](json_extract_keys.sqlx)
287+
Returns all keys in the input JSON as an array of string
288+
289+
```sql
290+
SELECT bqutil.fn.json_extract_keys(
291+
'{"foo" : "cat", "bar": "dog", "hat": "rat"}'
292+
) AS keys_array
293+
294+
foo
295+
bar
296+
hat
297+
```
298+
299+
### [json_extract_values()](json_extract_values.sqlx)
300+
Returns all values in the input JSON as an array of string
301+
302+
```sql
303+
SELECT bqutil.fn.json_extract_values(
304+
'{"foo" : "cat", "bar": "dog", "hat": "rat"}'
305+
) AS keys_array
306+
307+
cat
308+
dog
309+
rat
310+
```
284311

285312
### [json_typeof(json string)](json_typeof.sqlx)
286313

@@ -463,10 +490,10 @@ SELECT
463490
Returns a binary representation of a number.
464491

465492
```sql
466-
SELECT
467-
x,
493+
SELECT
494+
x,
468495
bqutil.fn.to_binary(x) AS binary
469-
FROM
496+
FROM
470497
UNNEST([1, 123456, 9876543210, -1001]) AS x;
471498
```
472499

@@ -484,15 +511,15 @@ results:
484511
Returns a hexadecimal representation of a number.
485512

486513
```sql
487-
SELECT
488-
x,
514+
SELECT
515+
x,
489516
bqutil.fn.to_hex(x) AS hex
490-
FROM
517+
FROM
491518
UNNEST([1, 123456, 9876543210, -1001]) AS x;
492519
```
493520

494521
results:
495-
| x | hex |
522+
| x | hex |
496523
|------------|------------------|
497524
| 1 | 0000000000000001 |
498525
| 123456 | 000000000001e240 |
@@ -705,11 +732,11 @@ results:
705732
Returns the number of weeks from the beginning of the month to the specified date. The result is an INTEGER value between 1 and 5, representing the nth occurrence of the week in the month. The value 0 means the partial week.
706733

707734
```sql
708-
SELECT
709-
bqutil.fn.week_of_month(DATE '2020-07-01'),
735+
SELECT
736+
bqutil.fn.week_of_month(DATE '2020-07-01'),
710737
bqutil.fn.week_of_month(DATE '2020-07-08');
711-
712-
0 1
738+
739+
0 1
713740
```
714741

715742
### [y4md_to_date(y4md STRING)](y4md_to_date.sqlx)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
config { hasOutput: true }
2+
/*
3+
* Copyright 2021 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/*
19+
Returns all keys in the input JSON as an array of string
20+
*/
21+
CREATE OR REPLACE FUNCTION ${self()}(input STRING)
22+
RETURNS Array<String>
23+
LANGUAGE js AS """
24+
return Object.keys(JSON.parse(input));
25+
""";
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
config { hasOutput: true }
2+
/*
3+
* Copyright 2021 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/*
19+
Returns all values in the input JSON as an array of string
20+
*/
21+
CREATE OR REPLACE FUNCTION ${self()}(input STRING)
22+
RETURNS Array<String>
23+
LANGUAGE js AS """
24+
return Object.values(JSON.parse(input));
25+
""";

udfs/community/test_cases.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@ generate_udf_test("int", [
4040
expected_output: `CAST(7 AS INT64)`
4141
},
4242
]);
43+
generate_udf_test("json_extract_keys", [
44+
{
45+
inputs: [`'{"foo" : "cat", "bar": "dog", "hat": "rat"}'`],
46+
expected_output: `["foo", "bar", "hat"]`
47+
},
48+
{
49+
inputs: [`'{"int" : 1}'`],
50+
expected_output: `["int"]`
51+
},
52+
]);
53+
generate_udf_test("json_extract_values", [
54+
{
55+
inputs: [`'{"foo" : "cat", "bar": "dog", "hat": "rat"}'`],
56+
expected_output: `["cat", "dog", "rat"]`
57+
},
58+
{
59+
inputs: [`'{"int" : 1}'`],
60+
expected_output: `["1"]`
61+
},
62+
]);
4363
generate_udf_test("json_typeof", [
4464
{
4565
inputs: [`'""'`],

0 commit comments

Comments
 (0)