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

BigQuery: Use TableListItem for table listing. #4427

Merged
merged 6 commits into from
Nov 20, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 5 additions & 3 deletions bigquery/google/cloud/bigquery/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from google.cloud.bigquery.dataset import Dataset
from google.cloud.bigquery.dataset import DatasetReference
from google.cloud.bigquery.table import Table, _TABLE_HAS_NO_SCHEMA
from google.cloud.bigquery.table import TableListItem

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

from google.cloud.bigquery.table import TableReference
from google.cloud.bigquery.table import _row_from_mapping
from google.cloud.bigquery.job import CopyJob
Expand Down Expand Up @@ -405,8 +406,9 @@ def list_dataset_tables(self, dataset, max_results=None, page_token=None,
:param retry: (Optional) How to retry the RPC.

:rtype: :class:`~google.api_core.page_iterator.Iterator`
:returns: Iterator of :class:`~google.cloud.bigquery.table.Table`
contained within the current dataset.
:returns:
Iterator of :class:`~google.cloud.bigquery.table.TableListItem`
contained within the current dataset.
"""
if not isinstance(dataset, (Dataset, DatasetReference)):
raise TypeError('dataset must be a Dataset or a DatasetReference')
Expand Down Expand Up @@ -1367,7 +1369,7 @@ def _item_to_table(iterator, resource):
:rtype: :class:`~google.cloud.bigquery.table.Table`
:returns: The next table in the page.
"""
return Table.from_api_repr(resource)
return TableListItem(resource)


def _make_job_id(job_id, prefix=None):
Expand Down
131 changes: 131 additions & 0 deletions bigquery/google/cloud/bigquery/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,137 @@ def _build_resource(self, filter_fields):
return resource


class TableListItem(object):
"""Read-only table resource object with a subset of table properties.

This comment was marked as spam.

This comment was marked as spam.


See
https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/list

Args:
resource (dict): A table resource object from a table list response.
"""

def __init__(self, resource):
self._properties = resource

@property
def project(self):
"""The project ID of the project this table belongs to.

Returns:
str: the project ID of the table.
"""
return self._properties.get('tableReference', {}).get('projectId')

@property
def dataset_id(self):
"""The dataset ID of the dataset this table belongs to.

Returns:
str: the dataset ID of the table.
"""
return self._properties.get('tableReference', {}).get('datasetId')

@property
def table_id(self):
"""The table ID.

Returns:
str: the table ID.
"""
return self._properties.get('tableReference', {}).get('tableId')

@property
def reference(self):
"""A :class:`~google.cloud.bigquery.table.TableReference` pointing to
this table.

Returns:
google.cloud.bigquery.table.TableReference: pointer to this table
"""
from google.cloud.bigquery import dataset

dataset_ref = dataset.DatasetReference(self.project, self.dataset_id)
return TableReference(dataset_ref, self.table_id)

@property
def labels(self):
"""Labels for the table.

This method always returns a dict. To change a table's labels,
modify the dict, then call ``Client.update_table``. To delete a
label, set its value to ``None`` before updating.

Returns:
Map[str, str]: A dictionary of the the table's labels
"""
return self._properties.get('labels', {})

@property
def full_table_id(self):
"""ID for the table, in the form ``project_id:dataset_id:table_id``.

Returns:
str: The fully-qualified ID of the table
"""
return self._properties.get('id')

@property
def table_type(self):
"""The type of the table.

Possible values are "TABLE", "VIEW", or "EXTERNAL".

Returns:
str: The kind of table
"""
return self._properties.get('type')

@property
def partitioning_type(self):
"""Time partitioning of the table.

Returns:
str:
Type of partitioning if the table is partitioned, None
otherwise.
"""
return self._properties.get('timePartitioning', {}).get('type')

@property
def partition_expiration(self):
"""Expiration time in ms for a partition

Returns:
int: The time in ms for partition expiration
"""
return int(
self._properties.get('timePartitioning', {}).get('expirationMs'))

@property
def friendly_name(self):
"""Title of the table.

Returns:
str: The name as set by the user, or None (the default)
"""
return self._properties.get('friendlyName')

@property
def view_use_legacy_sql(self):
"""Specifies whether to execute the view with Legacy or Standard SQL.

If this table is not a view, None is returned.

Returns:
bool: True if the view is using legacy SQL, or None if not a view
"""
view = self._properties.get('view', {})
if self.table_type == 'VIEW':
# The server-side default for useLegacySql is True.
return view.get('useLegacySql', True)


def _row_from_mapping(mapping, schema):
"""Convert a mapping to a row tuple using the schema.

Expand Down
8 changes: 4 additions & 4 deletions bigquery/tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ def test_list_dataset_tables_empty(self):
self.assertEqual(req['path'], '/%s' % PATH)

def test_list_dataset_tables_defaults(self):
from google.cloud.bigquery.table import Table
from google.cloud.bigquery.table import TableListItem

TABLE_1 = 'table_one'
TABLE_2 = 'table_two'
Expand Down Expand Up @@ -1039,7 +1039,7 @@ def test_list_dataset_tables_defaults(self):

self.assertEqual(len(tables), len(DATA['tables']))
for found, expected in zip(tables, DATA['tables']):
self.assertIsInstance(found, Table)
self.assertIsInstance(found, TableListItem)
self.assertEqual(found.full_table_id, expected['id'])
self.assertEqual(found.table_type, expected['type'])
self.assertEqual(token, TOKEN)
Expand All @@ -1050,7 +1050,7 @@ def test_list_dataset_tables_defaults(self):
self.assertEqual(req['path'], '/%s' % PATH)

def test_list_dataset_tables_explicit(self):
from google.cloud.bigquery.table import Table
from google.cloud.bigquery.table import TableListItem

TABLE_1 = 'table_one'
TABLE_2 = 'table_two'
Expand Down Expand Up @@ -1087,7 +1087,7 @@ def test_list_dataset_tables_explicit(self):

self.assertEqual(len(tables), len(DATA['tables']))
for found, expected in zip(tables, DATA['tables']):
self.assertIsInstance(found, Table)
self.assertIsInstance(found, TableListItem)
self.assertEqual(found.full_table_id, expected['id'])
self.assertEqual(found.table_type, expected['type'])
self.assertIsNone(token)
Expand Down
83 changes: 83 additions & 0 deletions bigquery/tests/unit/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,89 @@ def test__row_from_mapping_w_schema(self):
('Phred Phlyntstone', 32, ['red', 'green'], None))


class TestTableListItem(unittest.TestCase):

@staticmethod
def _get_target_class():
from google.cloud.bigquery.table import TableListItem

return TableListItem

def _make_one(self, *args, **kw):
return self._get_target_class()(*args, **kw)

def test_ctor(self):
project = 'test-project'
dataset_id = 'test_dataset'
table_id = 'coffee_table'
resource = {
'kind': 'bigquery#table',
'id': '{}:{}:{}'.format(project, dataset_id, table_id),
'tableReference': {
'projectId': project,
'datasetId': dataset_id,
'tableId': table_id,
},
'friendlyName': 'Mahogany Coffee Table',
'type': 'TABLE',
'timePartitioning': {
'type': 'DAY',
'expirationMs': '10000',
},
'labels': {
'some-stuff': 'this-is-a-label',
},
}

table = self._make_one(resource)
self.assertEqual(table.project, project)
self.assertEqual(table.dataset_id, dataset_id)
self.assertEqual(table.table_id, table_id)
self.assertEqual(
table.full_table_id,
'{}:{}:{}'.format(project, dataset_id, table_id))
self.assertEqual(table.reference.project, project)
self.assertEqual(table.reference.dataset_id, dataset_id)
self.assertEqual(table.reference.table_id, table_id)
self.assertEqual(table.friendly_name, 'Mahogany Coffee Table')
self.assertEqual(table.table_type, 'TABLE')
self.assertEqual(table.partitioning_type, 'DAY')
self.assertEqual(table.partition_expiration, 10000)
self.assertEqual(table.labels['some-stuff'], 'this-is-a-label')
self.assertIsNone(table.view_use_legacy_sql)

def test_ctor_view(self):
project = 'test-project'
dataset_id = 'test_dataset'
table_id = 'just_looking'
resource = {
'kind': 'bigquery#table',
'id': '{}:{}:{}'.format(project, dataset_id, table_id),
'tableReference': {
'projectId': project,
'datasetId': dataset_id,
'tableId': table_id,
},
'type': 'VIEW',
'view': {
'useLegacySql': False,
},
}

table = self._make_one(resource)
self.assertEqual(table.project, project)
self.assertEqual(table.dataset_id, dataset_id)
self.assertEqual(table.table_id, table_id)
self.assertEqual(
table.full_table_id,
'{}:{}:{}'.format(project, dataset_id, table_id))
self.assertEqual(table.reference.project, project)
self.assertEqual(table.reference.dataset_id, dataset_id)
self.assertEqual(table.reference.table_id, table_id)
self.assertEqual(table.table_type, 'VIEW')
self.assertFalse(table.view_use_legacy_sql)


class TestRow(unittest.TestCase):

def test_row(self):
Expand Down