Skip to content

Commit

Permalink
Merge pull request #2892 from tseaver/2887-bigquery-struct-query-parm
Browse files Browse the repository at this point in the history
Conform to expected wire format for struct query parameters.
  • Loading branch information
tseaver authored Dec 21, 2016
2 parents d51d3ac + 16707a1 commit 455eaf6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 16 deletions.
12 changes: 8 additions & 4 deletions bigquery/google/cloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ def to_api_repr(self):
values = [converter(value) for value in values]
resource = {
'parameterType': {
'type': 'ARRAY',
'arrayType': self.array_type,
},
'parameterValue': {
Expand Down Expand Up @@ -554,10 +555,12 @@ def from_api_repr(cls, resource):
instance = cls(name)
types = instance.struct_types
for item in resource['parameterType']['structTypes']:
types[item['name']] = item['type']
types[item['name']] = item['type']['type']
struct_values = resource['parameterValue']['structValues']
for key, value in struct_values.items():
converted = _CELLDATA_FROM_JSON[types[key]](value, None)
type_ = types[key]
value = value['value']
converted = _CELLDATA_FROM_JSON[type_](value, None)
instance.struct_values[key] = converted
return instance

Expand All @@ -568,18 +571,19 @@ def to_api_repr(self):
:returns: JSON mapping
"""
types = [
{'name': key, 'type': value}
{'name': key, 'type': {'type': value}}
for key, value in self.struct_types.items()
]
values = {}
for name, value in self.struct_values.items():
converter = _SCALAR_VALUE_TO_JSON.get(self.struct_types[name])
if converter is not None:
value = converter(value)
values[name] = value
values[name] = {'value': value}

resource = {
'parameterType': {
'type': 'STRUCT',
'structTypes': types,
},
'parameterValue': {
Expand Down
44 changes: 32 additions & 12 deletions bigquery/unit_tests/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,7 @@ def test_from_api_repr_w_name(self):
def test_from_api_repr_wo_name(self):
RESOURCE = {
'parameterType': {
'type': 'ARRAY',
'arrayType': 'INT64',
},
'parameterValue': {
Expand All @@ -1098,6 +1099,7 @@ def test_to_api_repr_w_name(self):
EXPECTED = {
'name': 'foo',
'parameterType': {
'type': 'ARRAY',
'arrayType': 'INT64',
},
'parameterValue': {
Expand All @@ -1110,6 +1112,7 @@ def test_to_api_repr_w_name(self):
def test_to_api_repr_wo_name(self):
EXPECTED = {
'parameterType': {
'type': 'ARRAY',
'arrayType': 'INT64',
},
'parameterValue': {
Expand All @@ -1123,6 +1126,7 @@ def test_to_api_repr_wo_name(self):
def test_to_api_repr_w_unknown_type(self):
EXPECTED = {
'parameterType': {
'type': 'ARRAY',
'arrayType': 'UNKNOWN',
},
'parameterValue': {
Expand Down Expand Up @@ -1170,13 +1174,17 @@ def test_from_api_repr_w_name(self):
RESOURCE = {
'name': 'foo',
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': 'INT64'},
{'name': 'baz', 'type': 'STRING'},
{'name': 'bar', 'type': {'type': 'INT64'}},
{'name': 'baz', 'type': {'type': 'STRING'}},
],
},
'parameterValue': {
'structValues': {'bar': 123, 'baz': 'abc'},
'structValues': {
'bar': {'value': 123},
'baz': {'value': 'abc'},
},
},
}
klass = self._get_target_class()
Expand All @@ -1188,13 +1196,17 @@ def test_from_api_repr_w_name(self):
def test_from_api_repr_wo_name(self):
RESOURCE = {
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': 'INT64'},
{'name': 'baz', 'type': 'STRING'},
{'name': 'bar', 'type': {'type': 'INT64'}},
{'name': 'baz', 'type': {'type': 'STRING'}},
],
},
'parameterValue': {
'structValues': {'bar': 123, 'baz': 'abc'},
'structValues': {
'bar': {'value': 123},
'baz': {'value': 'abc'},
},
},
}
klass = self._get_target_class()
Expand All @@ -1207,13 +1219,17 @@ def test_to_api_repr_w_name(self):
EXPECTED = {
'name': 'foo',
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': 'INT64'},
{'name': 'baz', 'type': 'STRING'},
{'name': 'bar', 'type': {'type': 'INT64'}},
{'name': 'baz', 'type': {'type': 'STRING'}},
],
},
'parameterValue': {
'structValues': {'bar': '123', 'baz': 'abc'},
'structValues': {
'bar': {'value': '123'},
'baz': {'value': 'abc'},
},
},
}
sub_1 = self._make_subparam('bar', 'INT64', 123)
Expand All @@ -1224,13 +1240,17 @@ def test_to_api_repr_w_name(self):
def test_to_api_repr_wo_name(self):
EXPECTED = {
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': 'INT64'},
{'name': 'baz', 'type': 'STRING'},
{'name': 'bar', 'type': {'type': 'INT64'}},
{'name': 'baz', 'type': {'type': 'STRING'}},
],
},
'parameterValue': {
'structValues': {'bar': '123', 'baz': 'abc'},
'structValues': {
'bar': {'value': '123'},
'baz': {'value': 'abc'},
},
},
}
sub_1 = self._make_subparam('bar', 'INT64', 123)
Expand Down
14 changes: 14 additions & 0 deletions system_tests/bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,20 @@ def test_sync_query_w_standard_sql_types(self):
import datetime
from google.cloud._helpers import UTC
from google.cloud.bigquery._helpers import ScalarQueryParameter
from google.cloud.bigquery._helpers import StructQueryParameter
naive = datetime.datetime(2016, 12, 5, 12, 41, 9)
stamp = "%s %s" % (naive.date().isoformat(), naive.time().isoformat())
zoned = naive.replace(tzinfo=UTC)
zoned_param = ScalarQueryParameter(
name='zoned', type_='TIMESTAMP', value=zoned)
question = 'What is the answer to life, the universe, and everything?'
question_param = ScalarQueryParameter(
name='question', type_='STRING', value=question)
answer = 42
answer_param = ScalarQueryParameter(
name='answer', type_='INT64', value=answer)
struct_param = StructQueryParameter(
'hitchhiker', question_param, answer_param)
EXAMPLES = [
{
'sql': 'SELECT 1',
Expand Down Expand Up @@ -561,6 +570,11 @@ def test_sync_query_w_standard_sql_types(self):
'expected': zoned,
'query_parameters': [zoned_param],
},
{
'sql': 'SELECT (@hitchhiker.question, @hitchhiker.answer)',
'expected': ({'_field_1': question, '_field_2': answer}),
'query_parameters': [struct_param],
},
]
for example in EXAMPLES:
query = Config.CLIENT.run_sync_query(
Expand Down

0 comments on commit 455eaf6

Please sign in to comment.