Skip to content

Commit 1c6fe85

Browse files
committed
feat: add bigframes.bigquery.to_json_string
1 parent 36ee4d1 commit 1c6fe85

File tree

5 files changed

+65
-6
lines changed

5 files changed

+65
-6
lines changed

bigframes/bigquery/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
json_value,
5151
json_value_array,
5252
parse_json,
53+
to_json_string,
5354
)
5455
from bigframes.bigquery._operations.search import create_vector_index, vector_search
5556
from bigframes.bigquery._operations.sql import sql_scalar
@@ -87,6 +88,7 @@
8788
json_value,
8889
json_value_array,
8990
parse_json,
91+
to_json_string,
9092
# search ops
9193
create_vector_index,
9294
vector_search,

bigframes/bigquery/_operations/json.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,40 @@ def json_value_array(
430430
return input._apply_unary_op(ops.JSONValueArray(json_path=json_path))
431431

432432

433+
def to_json_string(
434+
input: series.Series,
435+
) -> series.Series:
436+
"""Converts a series to a JSON-formatted STRING value.
437+
438+
**Examples:**
439+
440+
>>> import bigframes.pandas as bpd
441+
>>> import bigframes.bigquery as bbq
442+
>>> bpd.options.display.progress_bar = None
443+
444+
>>> s = bpd.Series([1, 2, 3])
445+
>>> bbq.to_json_string(s)
446+
0 1
447+
1 2
448+
2 3
449+
dtype: string
450+
451+
>>> s = bpd.Series([{"int": 1, "str": "pandas"}, {"int": 2, "str": "numpy"}])
452+
>>> bbq.to_json_string(s)
453+
0 {"int":1,"str":"pandas"}
454+
1 {"int":2,"str":"numpy"}
455+
dtype: string
456+
457+
Args:
458+
input (bigframes.series.Series):
459+
The Series to be converted.
460+
461+
Returns:
462+
bigframes.series.Series: A new Series with the JSON-formatted STRING value.
463+
"""
464+
return input._apply_unary_op(ops.ToJSONString())
465+
466+
433467
@utils.preview(name="The JSON-related API `parse_json`")
434468
def parse_json(
435469
input: series.Series,

bigframes/core/compile/ibis_compiler/scalar_op_registry.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,9 +2068,7 @@ def json_extract_string_array( # type: ignore[empty-body]
20682068

20692069

20702070
@ibis_udf.scalar.builtin(name="to_json_string")
2071-
def to_json_string( # type: ignore[empty-body]
2072-
json_obj: ibis_dtypes.JSON,
2073-
) -> ibis_dtypes.String:
2071+
def to_json_string(json_obj) -> ibis_dtypes.String: # type: ignore[empty-body]
20742072
"""Convert JSON to STRING."""
20752073

20762074

bigframes/operations/json_ops.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ class ToJSONString(base_ops.UnaryOp):
108108

109109
def output_type(self, *input_types):
110110
input_type = input_types[0]
111-
if not dtypes.is_json_like(input_type):
111+
if not dtypes.is_json_encoding_type(input_type):
112112
raise TypeError(
113-
"Input type must be a valid JSON object or JSON-formatted string type."
114-
+ f" Received type: {input_type}"
113+
"The value to be assigned must be a type that can be encoded as JSON."
114+
+ f"Received type: {input_type}"
115115
)
116116
return dtypes.STRING_DTYPE
117117

tests/system/small/bigquery/test_json.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,28 @@ def test_parse_json_w_invalid_series_type():
384384
s = bpd.Series([1, 2])
385385
with pytest.raises(TypeError):
386386
bbq.parse_json(s)
387+
388+
389+
def test_to_json_string_from_int():
390+
s = bpd.Series([1, 2, None, 3])
391+
actual = bbq.to_json_string(s)
392+
expected = bpd.Series(["1", "2", "null", "3"], dtype=dtypes.STRING_DTYPE)
393+
pd.testing.assert_series_equal(actual.to_pandas(), expected.to_pandas())
394+
395+
396+
def test_to_json_string_from_struct():
397+
s = bpd.Series(
398+
[
399+
{"version": 1, "project": "pandas"},
400+
{"version": 2, "project": "numpy"},
401+
]
402+
)
403+
assert dtypes.is_struct_like(s.dtype)
404+
405+
actual = bbq.to_json_string(s)
406+
expected = bpd.Series(
407+
['{"project":"pandas","version":1}', '{"project":"numpy","version":2}'],
408+
dtype=dtypes.STRING_DTYPE,
409+
)
410+
411+
pd.testing.assert_series_equal(actual.to_pandas(), expected.to_pandas())

0 commit comments

Comments
 (0)