diff --git a/google/cloud/bigquery/_helpers.py b/google/cloud/bigquery/_helpers.py index 13baea4ad..93b46341e 100644 --- a/google/cloud/bigquery/_helpers.py +++ b/google/cloud/bigquery/_helpers.py @@ -239,6 +239,15 @@ def _record_from_json(value, field): return record +def _json_from_json(value, field): + """Coerce 'value' to a Pythonic JSON representation.""" + if _not_null(value, field): + return json.loads(value) + else: + return None + + +# Parse BigQuery API response JSON into a Python representation. _CELLDATA_FROM_JSON = { "INTEGER": _int_from_json, "INT64": _int_from_json, @@ -257,6 +266,7 @@ def _record_from_json(value, field): "DATE": _date_from_json, "TIME": _time_from_json, "RECORD": _record_from_json, + "JSON": _json_from_json, } _QUERY_PARAMS_FROM_JSON = dict(_CELLDATA_FROM_JSON) @@ -413,13 +423,8 @@ def _time_to_json(value): return value -def _json_from_json(value, field): - """Coerce 'value' to a pythonic JSON representation, if set or not nullable.""" - if _not_null(value, field): - return json.loads(value) - - -# Converters used for scalar values marshalled as row data. +# Converters used for scalar values marshalled to the BigQuery API, such as in +# query parameters or the tabledata.insert API. _SCALAR_VALUE_TO_JSON_ROW = { "INTEGER": _int_to_json, "INT64": _int_to_json, diff --git a/tests/unit/test__helpers.py b/tests/unit/test__helpers.py index 3c425da5f..7bf55baeb 100644 --- a/tests/unit/test__helpers.py +++ b/tests/unit/test__helpers.py @@ -15,6 +15,7 @@ import base64 import datetime import decimal +import json import unittest import mock @@ -71,9 +72,20 @@ def test_w_none_required(self): with self.assertRaises(TypeError): self._call_fut(None, _Field("REQUIRED")) + def test_w_json_field(self): + data_field = _Field("REQUIRED", "data", "JSON") + + value = json.dumps( + {"v": {"key": "value"}}, + ) + + expected_output = {"v": {"key": "value"}} + coerced_output = self._call_fut(value, data_field) + self.assertEqual(coerced_output, expected_output) + def test_w_string_value(self): - coerced = self._call_fut('{"foo": true}', object()) - self.assertEqual(coerced, {"foo": True}) + coerced = self._call_fut('"foo"', object()) + self.assertEqual(coerced, "foo") class Test_float_from_json(unittest.TestCase):