Skip to content

Commit 1b764b8

Browse files
tseaverlukesneeringer
authored andcommitted
Add 'Table.row_from_mapping' helper. (googleapis#3425)
1 parent 10466d1 commit 1b764b8

2 files changed

Lines changed: 87 additions & 3 deletions

File tree

bigquery/google/cloud/bigquery/table.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,35 @@ def fetch_data(self, max_results=None, page_token=None, client=None):
733733
iterator._NEXT_TOKEN = 'pageToken'
734734
return iterator
735735

736+
def row_from_mapping(self, mapping):
737+
"""Convert a mapping to a row tuple using the schema.
738+
739+
:type mapping: dict
740+
:param mapping: Mapping of row data: must contain keys for all
741+
required fields in the schema. Keys which do not correspond
742+
to a field in the schema are ignored.
743+
744+
:rtype: tuple
745+
:returns: Tuple whose elements are ordered according to the table's
746+
schema.
747+
:raises: ValueError if table's schema is not set
748+
"""
749+
if len(self._schema) == 0:
750+
raise ValueError(_TABLE_HAS_NO_SCHEMA)
751+
752+
row = []
753+
for field in self.schema:
754+
if field.mode == 'REQUIRED':
755+
row.append(mapping[field.name])
756+
elif field.mode == 'REPEATED':
757+
row.append(mapping.get(field.name, ()))
758+
elif field.mode == 'NULLABLE':
759+
row.append(mapping.get(field.name))
760+
else:
761+
raise ValueError(
762+
"Unknown field mode: {}".format(field.mode))
763+
return tuple(row)
764+
736765
def insert_data(self,
737766
rows,
738767
row_ids=None,

bigquery/tests/unit/test_table.py

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,61 @@ def test_fetch_data_w_record_schema(self):
13471347
self.assertEqual(req['method'], 'GET')
13481348
self.assertEqual(req['path'], '/%s' % PATH)
13491349

1350+
def test_row_from_mapping_wo_schema(self):
1351+
from google.cloud.bigquery.table import _TABLE_HAS_NO_SCHEMA
1352+
MAPPING = {'full_name': 'Phred Phlyntstone', 'age': 32}
1353+
client = _Client(project=self.PROJECT)
1354+
dataset = _Dataset(client)
1355+
table = self._make_one(self.TABLE_NAME, dataset=dataset)
1356+
1357+
with self.assertRaises(ValueError) as exc:
1358+
table.row_from_mapping(MAPPING)
1359+
1360+
self.assertEqual(exc.exception.args, (_TABLE_HAS_NO_SCHEMA,))
1361+
1362+
def test_row_from_mapping_w_invalid_schema(self):
1363+
from google.cloud.bigquery.table import SchemaField
1364+
MAPPING = {
1365+
'full_name': 'Phred Phlyntstone',
1366+
'age': 32,
1367+
'colors': ['red', 'green'],
1368+
'bogus': 'WHATEVER',
1369+
}
1370+
client = _Client(project=self.PROJECT)
1371+
dataset = _Dataset(client)
1372+
full_name = SchemaField('full_name', 'STRING', mode='REQUIRED')
1373+
age = SchemaField('age', 'INTEGER', mode='REQUIRED')
1374+
colors = SchemaField('colors', 'DATETIME', mode='REPEATED')
1375+
bogus = SchemaField('joined', 'STRING', mode='BOGUS')
1376+
table = self._make_one(self.TABLE_NAME, dataset=dataset,
1377+
schema=[full_name, age, colors, bogus])
1378+
1379+
with self.assertRaises(ValueError) as exc:
1380+
table.row_from_mapping(MAPPING)
1381+
1382+
self.assertIn('Unknown field mode: BOGUS', str(exc.exception))
1383+
1384+
def test_row_from_mapping_w_schema(self):
1385+
from google.cloud.bigquery.table import SchemaField
1386+
MAPPING = {
1387+
'full_name': 'Phred Phlyntstone',
1388+
'age': 32,
1389+
'colors': ['red', 'green'],
1390+
'extra': 'IGNORED',
1391+
}
1392+
client = _Client(project=self.PROJECT)
1393+
dataset = _Dataset(client)
1394+
full_name = SchemaField('full_name', 'STRING', mode='REQUIRED')
1395+
age = SchemaField('age', 'INTEGER', mode='REQUIRED')
1396+
colors = SchemaField('colors', 'DATETIME', mode='REPEATED')
1397+
joined = SchemaField('joined', 'STRING', mode='NULLABLE')
1398+
table = self._make_one(self.TABLE_NAME, dataset=dataset,
1399+
schema=[full_name, age, colors, joined])
1400+
1401+
self.assertEqual(
1402+
table.row_from_mapping(MAPPING),
1403+
('Phred Phlyntstone', 32, ['red', 'green'], None))
1404+
13501405
def test_insert_data_wo_schema(self):
13511406
from google.cloud.bigquery.table import _TABLE_HAS_NO_SCHEMA
13521407

@@ -2055,7 +2110,7 @@ def test__parse_schema_resource_subfields(self):
20552110
RESOURCE['schema']['fields'].append(
20562111
{'name': 'phone',
20572112
'type': 'RECORD',
2058-
'mode': 'REPEATABLE',
2113+
'mode': 'REPEATED',
20592114
'fields': [{'name': 'type',
20602115
'type': 'STRING',
20612116
'mode': 'REQUIRED'},
@@ -2123,7 +2178,7 @@ def test_w_subfields(self):
21232178
full_name = SchemaField('full_name', 'STRING', mode='REQUIRED')
21242179
ph_type = SchemaField('type', 'STRING', 'REQUIRED')
21252180
ph_num = SchemaField('number', 'STRING', 'REQUIRED')
2126-
phone = SchemaField('phone', 'RECORD', mode='REPEATABLE',
2181+
phone = SchemaField('phone', 'RECORD', mode='REPEATED',
21272182
fields=[ph_type, ph_num])
21282183
resource = self._call_fut([full_name, phone])
21292184
self.assertEqual(len(resource), 2)
@@ -2134,7 +2189,7 @@ def test_w_subfields(self):
21342189
self.assertEqual(resource[1],
21352190
{'name': 'phone',
21362191
'type': 'RECORD',
2137-
'mode': 'REPEATABLE',
2192+
'mode': 'REPEATED',
21382193
'fields': [{'name': 'type',
21392194
'type': 'STRING',
21402195
'mode': 'REQUIRED'},

0 commit comments

Comments
 (0)