Skip to content

Commit 0d93073

Browse files
fix: Deserializing JSON subfields within structs fails (#1742)
… for deserializing json subfields from bigquery, this adds support for that. Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [x] Make sure to open an issue as a [bug/issue](https://togithub.com/googleapis/python-bigquery/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [x] Ensure the tests and linter pass - [x] Code coverage does not decrease (if any source code was changed) - [x] Appropriate docs were updated (if necessary) Fixes #[1500](https://togithub.com/googleapis/python-bigquery/issues/1500) 🦕
1 parent c9af8c1 commit 0d93073

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

google/cloud/bigquery/_helpers.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ def _record_from_json(value, field):
239239
return record
240240

241241

242+
def _json_from_json(value, field):
243+
"""Coerce 'value' to a Pythonic JSON representation."""
244+
if _not_null(value, field):
245+
return json.loads(value)
246+
else:
247+
return None
248+
249+
250+
# Parse BigQuery API response JSON into a Python representation.
242251
_CELLDATA_FROM_JSON = {
243252
"INTEGER": _int_from_json,
244253
"INT64": _int_from_json,
@@ -257,6 +266,7 @@ def _record_from_json(value, field):
257266
"DATE": _date_from_json,
258267
"TIME": _time_from_json,
259268
"RECORD": _record_from_json,
269+
"JSON": _json_from_json,
260270
}
261271

262272
_QUERY_PARAMS_FROM_JSON = dict(_CELLDATA_FROM_JSON)
@@ -413,13 +423,8 @@ def _time_to_json(value):
413423
return value
414424

415425

416-
def _json_from_json(value, field):
417-
"""Coerce 'value' to a pythonic JSON representation, if set or not nullable."""
418-
if _not_null(value, field):
419-
return json.loads(value)
420-
421-
422-
# Converters used for scalar values marshalled as row data.
426+
# Converters used for scalar values marshalled to the BigQuery API, such as in
427+
# query parameters or the tabledata.insert API.
423428
_SCALAR_VALUE_TO_JSON_ROW = {
424429
"INTEGER": _int_to_json,
425430
"INT64": _int_to_json,

tests/unit/test__helpers.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import base64
1616
import datetime
1717
import decimal
18+
import json
1819
import unittest
1920

2021
import mock
@@ -71,9 +72,20 @@ def test_w_none_required(self):
7172
with self.assertRaises(TypeError):
7273
self._call_fut(None, _Field("REQUIRED"))
7374

75+
def test_w_json_field(self):
76+
data_field = _Field("REQUIRED", "data", "JSON")
77+
78+
value = json.dumps(
79+
{"v": {"key": "value"}},
80+
)
81+
82+
expected_output = {"v": {"key": "value"}}
83+
coerced_output = self._call_fut(value, data_field)
84+
self.assertEqual(coerced_output, expected_output)
85+
7486
def test_w_string_value(self):
75-
coerced = self._call_fut('{"foo": true}', object())
76-
self.assertEqual(coerced, {"foo": True})
87+
coerced = self._call_fut('"foo"', object())
88+
self.assertEqual(coerced, "foo")
7789

7890

7991
class Test_float_from_json(unittest.TestCase):

0 commit comments

Comments
 (0)