Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add missing handler for deserializing json value #1587

Merged
merged 7 commits into from
Dec 13, 2023
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
8 changes: 8 additions & 0 deletions google/cloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import base64
import datetime
import decimal
import json
import math
import re
import os
Expand Down Expand Up @@ -412,6 +413,12 @@ 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.
_SCALAR_VALUE_TO_JSON_ROW = {
"INTEGER": _int_to_json,
Expand All @@ -427,6 +434,7 @@ def _time_to_json(value):
"DATETIME": _datetime_to_json,
"DATE": _date_to_json,
"TIME": _time_to_json,
"JSON": _json_from_json,
# Make sure DECIMAL and BIGDECIMAL are handled, even though
# requests for them should be converted to NUMERIC. Better safe
# than sorry.
Expand Down
6 changes: 3 additions & 3 deletions google/cloud/bigquery/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def to_api_repr(self) -> dict:
value = self.value
converter = _SCALAR_VALUE_TO_JSON_PARAM.get(self.type_)
if converter is not None:
value = converter(value)
value = converter(value) # type: ignore
resource: Dict[str, Any] = {
"parameterType": {"type": self.type_},
"parameterValue": {"value": value},
Expand Down Expand Up @@ -626,7 +626,7 @@ def to_api_repr(self) -> dict:

converter = _SCALAR_VALUE_TO_JSON_PARAM.get(a_type["type"])
if converter is not None:
values = [converter(value) for value in values]
values = [converter(value) for value in values] # type: ignore
a_values = [{"value": value} for value in values]

resource = {
Expand Down Expand Up @@ -775,7 +775,7 @@ def to_api_repr(self) -> dict:
s_types[name] = {"name": name, "type": {"type": type_}}
converter = _SCALAR_VALUE_TO_JSON_PARAM.get(type_)
if converter is not None:
value = converter(value)
value = converter(value) # type: ignore
values[name] = {"value": value}

resource = {
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ def test_w_float_value(self):
self.assertEqual(coerced, 42)


class Test_json_from_json(unittest.TestCase):
def _call_fut(self, value, field):
from google.cloud.bigquery._helpers import _json_from_json

return _json_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._call_fut(None, _Field("NULLABLE")))

def test_w_none_required(self):
with self.assertRaises(TypeError):
self._call_fut(None, _Field("REQUIRED"))

def test_w_string_value(self):
coerced = self._call_fut('{"foo": true}', object())
self.assertEqual(coerced, {"foo": True})


class Test_float_from_json(unittest.TestCase):
def _call_fut(self, value, field):
from google.cloud.bigquery._helpers import _float_from_json
Expand Down