Skip to content

Commit

Permalink
Merge pull request googleapis#3180 from tseaver/3029-bigquery-systest…
Browse files Browse the repository at this point in the history
…-query_params-nested

Add bigquery system tests for query parameters with nested types
  • Loading branch information
tseaver authored Mar 22, 2017
2 parents 4a422f3 + 0e46251 commit 6b99c5c
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 64 deletions.
56 changes: 37 additions & 19 deletions bigquery/google/cloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,18 +500,23 @@ def to_api_repr(self):
:returns: JSON mapping
"""
values = self.values
converter = _SCALAR_VALUE_TO_JSON.get(self.array_type)
if converter is not None:
values = [converter(value) for value in values]
if self.array_type == 'RECORD':
reprs = [value.to_api_repr() for value in values]
a_type = reprs[0]['parameterType']
a_values = [repr_['parameterValue'] for repr_ in reprs]
else:
a_type = {'type': self.array_type}
converter = _SCALAR_VALUE_TO_JSON.get(self.array_type)
if converter is not None:
values = [converter(value) for value in values]
a_values = [{'value': value} for value in values]
resource = {
'parameterType': {
'type': 'ARRAY',
'arrayType': {
'type': self.array_type,
},
'arrayType': a_type,
},
'parameterValue': {
'arrayValues': [{'value': value} for value in values],
'arrayValues': a_values,
},
}
if self.name is not None:
Expand All @@ -531,9 +536,18 @@ class StructQueryParameter(AbstractQueryParameter):
"""
def __init__(self, name, *sub_params):
self.name = name
self.struct_types = OrderedDict(
(sub.name, sub.type_) for sub in sub_params)
self.struct_values = {sub.name: sub.value for sub in sub_params}
types = self.struct_types = OrderedDict()
values = self.struct_values = {}
for sub in sub_params:
if isinstance(sub, self.__class__):
types[sub.name] = 'STRUCT'
values[sub.name] = sub
elif isinstance(sub, ArrayQueryParameter):
types[sub.name] = 'ARRAY'
values[sub.name] = sub
else:
types[sub.name] = sub.type_
values[sub.name] = sub.value

@classmethod
def positional(cls, *sub_params):
Expand Down Expand Up @@ -576,21 +590,25 @@ def to_api_repr(self):
:rtype: dict
:returns: JSON mapping
"""
types = [
{'name': key, 'type': {'type': value}}
for key, value in self.struct_types.items()
]
s_types = {}
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': value}
type_ = self.struct_types[name]
if type_ in ('STRUCT', 'ARRAY'):
repr_ = value.to_api_repr()
s_types[name] = {'name': name, 'type': repr_['parameterType']}
values[name] = repr_['parameterValue']
else:
s_types[name] = {'name': name, 'type': {'type': type_}}
converter = _SCALAR_VALUE_TO_JSON.get(type_)
if converter is not None:
value = converter(value)
values[name] = {'value': value}

resource = {
'parameterType': {
'type': 'STRUCT',
'structTypes': types,
'structTypes': [s_types[key] for key in self.struct_types],
},
'parameterValue': {
'structValues': values,
Expand Down
121 changes: 107 additions & 14 deletions bigquery/unit_tests/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,12 @@ def test_to_api_repr_w_unknown_type(self):
self.assertEqual(param.to_api_repr(), EXPECTED)


def _make_subparam(name, type_, value):
from google.cloud.bigquery._helpers import ScalarQueryParameter

return ScalarQueryParameter(name, type_, value)


class Test_ArrayQueryParameter(unittest.TestCase):

@staticmethod
Expand Down Expand Up @@ -1230,6 +1236,36 @@ def test_to_api_repr_w_unknown_type(self):
param = klass.positional(array_type='UNKNOWN', values=['unknown'])
self.assertEqual(param.to_api_repr(), EXPECTED)

def test_to_api_repr_w_record_type(self):
from google.cloud.bigquery._helpers import StructQueryParameter

EXPECTED = {
'parameterType': {
'type': 'ARRAY',
'arrayType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'foo', 'type': {'type': 'STRING'}},
{'name': 'bar', 'type': {'type': 'INT64'}},
],
},
},
'parameterValue': {
'arrayValues': [{
'structValues': {
'foo': {'value': 'Foo'},
'bar': {'value': '123'},
}
}]
},
}
one = _make_subparam('foo', 'STRING', 'Foo')
another = _make_subparam('bar', 'INT64', 123)
struct = StructQueryParameter.positional(one, another)
klass = self._get_target_class()
param = klass.positional(array_type='RECORD', values=[struct])
self.assertEqual(param.to_api_repr(), EXPECTED)


class Test_StructQueryParameter(unittest.TestCase):

Expand All @@ -1242,23 +1278,17 @@ def _get_target_class():
def _make_one(self, *args, **kw):
return self._get_target_class()(*args, **kw)

@staticmethod
def _make_subparam(name, type_, value):
from google.cloud.bigquery._helpers import ScalarQueryParameter

return ScalarQueryParameter(name, type_, value)

def test_ctor(self):
sub_1 = self._make_subparam('bar', 'INT64', 123)
sub_2 = self._make_subparam('baz', 'STRING', 'abc')
sub_1 = _make_subparam('bar', 'INT64', 123)
sub_2 = _make_subparam('baz', 'STRING', 'abc')
param = self._make_one('foo', sub_1, sub_2)
self.assertEqual(param.name, 'foo')
self.assertEqual(param.struct_types, {'bar': 'INT64', 'baz': 'STRING'})
self.assertEqual(param.struct_values, {'bar': 123, 'baz': 'abc'})

def test_positional(self):
sub_1 = self._make_subparam('bar', 'INT64', 123)
sub_2 = self._make_subparam('baz', 'STRING', 'abc')
sub_1 = _make_subparam('bar', 'INT64', 123)
sub_2 = _make_subparam('baz', 'STRING', 'abc')
klass = self._get_target_class()
param = klass.positional(sub_1, sub_2)
self.assertEqual(param.name, None)
Expand Down Expand Up @@ -1327,8 +1357,8 @@ def test_to_api_repr_w_name(self):
},
},
}
sub_1 = self._make_subparam('bar', 'INT64', 123)
sub_2 = self._make_subparam('baz', 'STRING', 'abc')
sub_1 = _make_subparam('bar', 'INT64', 123)
sub_2 = _make_subparam('baz', 'STRING', 'abc')
param = self._make_one('foo', sub_1, sub_2)
self.assertEqual(param.to_api_repr(), EXPECTED)

Expand All @@ -1348,12 +1378,75 @@ def test_to_api_repr_wo_name(self):
},
},
}
sub_1 = self._make_subparam('bar', 'INT64', 123)
sub_2 = self._make_subparam('baz', 'STRING', 'abc')
sub_1 = _make_subparam('bar', 'INT64', 123)
sub_2 = _make_subparam('baz', 'STRING', 'abc')
klass = self._get_target_class()
param = klass.positional(sub_1, sub_2)
self.assertEqual(param.to_api_repr(), EXPECTED)

def test_to_api_repr_w_nested_array(self):
from google.cloud.bigquery._helpers import ArrayQueryParameter

EXPECTED = {
'name': 'foo',
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': {'type': 'STRING'}},
{'name': 'baz', 'type': {
'type': 'ARRAY',
'arrayType': {'type': 'INT64'},
}},
],
},
'parameterValue': {
'structValues': {
'bar': {'value': 'abc'},
'baz': {'arrayValues': [
{'value': '123'},
{'value': '456'},
]},
},
},
}
scalar = _make_subparam('bar', 'STRING', 'abc')
array = ArrayQueryParameter('baz', 'INT64', [123, 456])
param = self._make_one('foo', scalar, array)
self.assertEqual(param.to_api_repr(), EXPECTED)

def test_to_api_repr_w_nested_struct(self):
EXPECTED = {
'name': 'foo',
'parameterType': {
'type': 'STRUCT',
'structTypes': [
{'name': 'bar', 'type': {'type': 'STRING'}},
{'name': 'baz', 'type': {
'type': 'STRUCT',
'structTypes': [
{'name': 'qux', 'type': {'type': 'INT64'}},
{'name': 'spam', 'type': {'type': 'BOOL'}},
],
}},
],
},
'parameterValue': {
'structValues': {
'bar': {'value': 'abc'},
'baz': {'structValues': {
'qux': {'value': '123'},
'spam': {'value': 'true'},
}},
},
},
}
scalar_1 = _make_subparam('bar', 'STRING', 'abc')
scalar_2 = _make_subparam('qux', 'INT64', 123)
scalar_3 = _make_subparam('spam', 'BOOL', True)
sub = self._make_one('baz', scalar_2, scalar_3)
param = self._make_one('foo', scalar_1, sub)
self.assertEqual(param.to_api_repr(), EXPECTED)


class Test_QueryParametersProperty(unittest.TestCase):

Expand Down
Loading

0 comments on commit 6b99c5c

Please sign in to comment.