Skip to content
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
44 changes: 41 additions & 3 deletions bigquery/google/cloud/bigquery/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def table_id(self):
def table_type(self):
"""The type of the table.

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

:rtype: str, or ``NoneType``
:returns: the URL (None until set from the server).
Expand Down Expand Up @@ -364,13 +364,49 @@ def view_query(self, value):
"""
if not isinstance(value, six.string_types):
raise ValueError("Pass a string")
self._properties['view'] = {'query': value}
if self._properties.get('view') is None:
self._properties['view'] = {}
self._properties['view']['query'] = value

@view_query.deleter
def view_query(self):
"""Delete SQL query defining the table as a view."""
self._properties.pop('view', None)

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

If not set, None is returned. BigQuery's default mode is equivalent to
useLegacySql = True.

:rtype: bool, or ``NoneType``
:returns: The boolean for view.useLegacySql as set by the user, or
None (the default).
"""
view = self._properties.get('view')
if view is not None:
return view.get('useLegacySql')

@view_use_legacy_sql.setter
def view_use_legacy_sql(self, value):
"""Update the view sub-property 'useLegacySql'.

This boolean specifies whether to execute the view with legacy SQL
(True) or standard SQL (False). The default, if not specified, is
'True'.

:type value: bool
:param value: The boolean for view.useLegacySql

:raises: ValueError for invalid value types.
"""
if not isinstance(value, bool):
raise ValueError("Pass a boolean")
if self._properties.get('view') is None:
self._properties['view'] = {}
self._properties['view']['useLegacySql'] = value

def list_partitions(self, client=None):
"""List the partitions in a table.

Expand Down Expand Up @@ -470,6 +506,8 @@ def _build_resource(self):
if self.view_query is not None:
view = resource['view'] = {}
view['query'] = self.view_query
if self.view_use_legacy_sql is not None:
view['useLegacySql'] = self.view_use_legacy_sql

if self._schema:
resource['schema'] = {
Expand All @@ -479,7 +517,7 @@ def _build_resource(self):
return resource

def create(self, client=None):
"""API call: create the dataset via a PUT request
"""API call: create the table via a PUT request

See
https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/insert
Expand Down
24 changes: 22 additions & 2 deletions bigquery/tests/unit/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ def _verifyResourceProperties(self, table, resource):

if 'view' in resource:
self.assertEqual(table.view_query, resource['view']['query'])
self.assertEqual(table.view_use_legacy_sql, resource['view'].get('useLegacySql'))
else:
self.assertIsNone(table.view_query)
self.assertIsNone(table.view_use_legacy_sql)

if 'schema' in resource:
self._verifySchema(table.schema, resource)
Expand Down Expand Up @@ -160,6 +162,7 @@ def test_ctor(self):
self.assertIsNone(table.friendly_name)
self.assertIsNone(table.location)
self.assertIsNone(table.view_query)
self.assertIsNone(table.view_use_legacy_sql)

def test_ctor_w_schema(self):
from google.cloud.bigquery.table import SchemaField
Expand Down Expand Up @@ -358,6 +361,22 @@ def test_view_query_deleter(self):
del table.view_query
self.assertIsNone(table.view_query)

def test_view_use_legacy_sql_setter_bad_value(self):
client = _Client(self.PROJECT)
dataset = _Dataset(client)
table = self._make_one(self.TABLE_NAME, dataset)
with self.assertRaises(ValueError):
table.view_use_legacy_sql = 12345

def test_view_use_legacy_sql_setter(self):
client = _Client(self.PROJECT)
dataset = _Dataset(client)
table = self._make_one(self.TABLE_NAME, dataset)
table.view_use_legacy_sql = False
table.view_query = 'select * from foo'
self.assertEqual(table.view_use_legacy_sql, False)
self.assertEqual(table.view_query, 'select * from foo')

def test_from_api_repr_missing_identity(self):
self._setUpConstants()
client = _Client(self.PROJECT)
Expand Down Expand Up @@ -978,7 +997,7 @@ def test_update_w_alternate_client(self):
self.EXP_TIME = datetime.datetime(2015, 8, 1, 23, 59, 59,
tzinfo=UTC)
RESOURCE['expirationTime'] = _millis(self.EXP_TIME)
RESOURCE['view'] = {'query': QUERY}
RESOURCE['view'] = {'query': QUERY, 'useLegacySql': True}
RESOURCE['type'] = 'VIEW'
conn1 = _Connection()
client1 = _Client(project=self.PROJECT, connection=conn1)
Expand All @@ -990,6 +1009,7 @@ def test_update_w_alternate_client(self):
table.location = LOCATION
table.expires = self.EXP_TIME
table.view_query = QUERY
table.view_use_legacy_sql = True

table.update(client=client2)

Expand All @@ -1005,7 +1025,7 @@ def test_update_w_alternate_client(self):
'tableId': self.TABLE_NAME},
'expirationTime': _millis(self.EXP_TIME),
'location': 'EU',
'view': {'query': QUERY},
'view': {'query': QUERY, 'useLegacySql': True},
}
self.assertEqual(req['data'], SENT)
self._verifyResourceProperties(table, RESOURCE)
Expand Down