Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bigframes/bigquery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
json_value,
json_value_array,
parse_json,
to_json_string,
)
from bigframes.bigquery._operations.search import create_vector_index, vector_search
from bigframes.bigquery._operations.sql import sql_scalar
Expand Down Expand Up @@ -87,6 +88,7 @@
json_value,
json_value_array,
parse_json,
to_json_string,
# search ops
create_vector_index,
vector_search,
Expand Down
34 changes: 34 additions & 0 deletions bigframes/bigquery/_operations/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,40 @@ def json_value_array(
return input._apply_unary_op(ops.JSONValueArray(json_path=json_path))


def to_json_string(
input: series.Series,
) -> series.Series:
"""Converts a series to a JSON-formatted STRING value.
**Examples:**
>>> import bigframes.pandas as bpd
>>> import bigframes.bigquery as bbq
>>> bpd.options.display.progress_bar = None
>>> s = bpd.Series([1, 2, 3])
>>> bbq.to_json_string(s)
0 1
1 2
2 3
dtype: string
>>> s = bpd.Series([{"int": 1, "str": "pandas"}, {"int": 2, "str": "numpy"}])
>>> bbq.to_json_string(s)
0 {"int":1,"str":"pandas"}
1 {"int":2,"str":"numpy"}
dtype: string
Args:
input (bigframes.series.Series):
The Series to be converted.
Returns:
bigframes.series.Series: A new Series with the JSON-formatted STRING value.
"""
return input._apply_unary_op(ops.ToJSONString())


@utils.preview(name="The JSON-related API `parse_json`")
def parse_json(
input: series.Series,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2068,9 +2068,7 @@ def json_extract_string_array( # type: ignore[empty-body]


@ibis_udf.scalar.builtin(name="to_json_string")
def to_json_string( # type: ignore[empty-body]
value,
) -> ibis_dtypes.String:
def to_json_string(value) -> ibis_dtypes.String: # type: ignore[empty-body]
"""Convert value to JSON-formatted string."""


Expand Down
6 changes: 6 additions & 0 deletions bigframes/operations/json_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ class ToJSONString(base_ops.UnaryOp):
name: typing.ClassVar[str] = "to_json_string"

def output_type(self, *input_types):
input_type = input_types[0]
if not dtypes.is_json_encoding_type(input_type):
raise TypeError(
"The value to be assigned must be a type that can be encoded as JSON."
+ f"Received type: {input_type}"
)
return dtypes.STRING_DTYPE


Expand Down
25 changes: 25 additions & 0 deletions tests/system/small/bigquery/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,28 @@ def test_parse_json_w_invalid_series_type():
s = bpd.Series([1, 2])
with pytest.raises(TypeError):
bbq.parse_json(s)


def test_to_json_string_from_int():
s = bpd.Series([1, 2, None, 3])
actual = bbq.to_json_string(s)
expected = bpd.Series(["1", "2", "null", "3"], dtype=dtypes.STRING_DTYPE)
pd.testing.assert_series_equal(actual.to_pandas(), expected.to_pandas())


def test_to_json_string_from_struct():
s = bpd.Series(
[
{"version": 1, "project": "pandas"},
{"version": 2, "project": "numpy"},
]
)
assert dtypes.is_struct_like(s.dtype)

actual = bbq.to_json_string(s)
expected = bpd.Series(
['{"project":"pandas","version":1}', '{"project":"numpy","version":2}'],
dtype=dtypes.STRING_DTYPE,
)

pd.testing.assert_series_equal(actual.to_pandas(), expected.to_pandas())