Skip to content

Commit 883bfe6

Browse files
committed
Merge pull request #1282 from tseaver/1278-sync_query_results_not_job
Don't treat synchronous query as a job
2 parents f7d0371 + 2262fa0 commit 883bfe6

File tree

9 files changed

+880
-765
lines changed

9 files changed

+880
-765
lines changed

docs/bigquery-usage.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -279,17 +279,17 @@ Run a query which can be expected to complete within bounded time:
279279
>>> query = """\
280280
SELECT count(*) AS age_count FROM dataset_name.person_ages
281281
"""
282-
>>> job = client.run_sync_query(query)
283-
>>> job.timeout_ms = 1000
284-
>>> job.run() # API request
282+
>>> query = client.run_sync_query(query)
283+
>>> query.timeout_ms = 1000
284+
>>> query.run() # API request
285285
>>> retry_count = 100
286286
>>> while retry_count > 0 and not job.complete:
287287
... retry_count -= 1
288288
... time.sleep(10)
289-
... job.reload() # API request
290-
>>> job.schema
289+
... query.reload() # API request
290+
>>> query.schema
291291
[{'name': 'age_count', 'type': 'integer', 'mode': 'nullable'}]
292-
>>> job.rows
292+
>>> query.rows
293293
[(15,)]
294294

295295
.. note::

gcloud/bigquery/_helpers.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def _record_from_json(value, field):
5858
def _string_from_json(value, _):
5959
return value
6060

61+
6162
_CELLDATA_FROM_JSON = {
6263
'INTEGER': _int_from_json,
6364
'FLOAT': _float_from_json,
@@ -81,3 +82,73 @@ def _rows_from_json(rows, schema):
8182
row_data.append(converter(cell['v'], field))
8283
rows_data.append(tuple(row_data))
8384
return rows_data
85+
86+
87+
class _ConfigurationProperty(object):
88+
"""Base property implementation.
89+
90+
Values will be stored on a `_configuration` helper attribute of the
91+
property's job instance.
92+
93+
:type name: string
94+
:param name: name of the property
95+
"""
96+
97+
def __init__(self, name):
98+
self.name = name
99+
self._backing_name = '_%s' % (self.name,)
100+
101+
def __get__(self, instance, owner):
102+
"""Descriptor protocal: accesstor"""
103+
if instance is None:
104+
return self
105+
return getattr(instance._configuration, self._backing_name)
106+
107+
def _validate(self, value):
108+
"""Subclasses override to impose validation policy."""
109+
pass
110+
111+
def __set__(self, instance, value):
112+
"""Descriptor protocal: mutator"""
113+
self._validate(value)
114+
setattr(instance._configuration, self._backing_name, value)
115+
116+
def __delete__(self, instance):
117+
"""Descriptor protocal: deleter"""
118+
delattr(instance._configuration, self._backing_name)
119+
120+
121+
class _TypedProperty(_ConfigurationProperty):
122+
"""Property implementation: validates based on value type.
123+
124+
:type name: string
125+
:param name: name of the property
126+
127+
:type property_type: type or sequence of types
128+
:param property_type: type to be validated
129+
"""
130+
def __init__(self, name, property_type):
131+
super(_TypedProperty, self).__init__(name)
132+
self.property_type = property_type
133+
134+
def _validate(self, value):
135+
if not isinstance(value, self.property_type):
136+
raise ValueError('Required type: %s' % (self.property_type,))
137+
138+
139+
class _EnumProperty(_ConfigurationProperty):
140+
"""Psedo-enumeration class.
141+
142+
Subclasses must define ``ALLOWED`` as a class-level constant: it must
143+
be a sequence of strings.
144+
145+
:type name: string
146+
:param name: name of the property
147+
"""
148+
def _validate(self, value):
149+
"""Check that ``value`` is one of the allowed values.
150+
151+
:raises: ValueError if value is not allowed.
152+
"""
153+
if value not in self.ALLOWED:
154+
raise ValueError('Pass one of: %s' ', '.join(self.ALLOWED))

gcloud/bigquery/client.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
from gcloud.bigquery.job import CopyJob
2222
from gcloud.bigquery.job import ExtractTableToStorageJob
2323
from gcloud.bigquery.job import LoadTableFromStorageJob
24-
from gcloud.bigquery.job import RunAsyncQueryJob
25-
from gcloud.bigquery.job import RunSyncQueryJob
24+
from gcloud.bigquery.job import QueryJob
25+
from gcloud.bigquery.query import QueryResults
2626

2727

2828
class Client(JSONClient):
@@ -179,18 +179,18 @@ def run_async_query(self, job_name, query):
179179
:type query: string
180180
:param query: SQL query to be executed
181181
182-
:rtype: :class:`gcloud.bigquery.job.RunAsyncQueryJob`
183-
:returns: a new ``RunAsyncQueryJob`` instance
182+
:rtype: :class:`gcloud.bigquery.job.QueryJob`
183+
:returns: a new ``QueryJob`` instance
184184
"""
185-
return RunAsyncQueryJob(job_name, query, client=self)
185+
return QueryJob(job_name, query, client=self)
186186

187187
def run_sync_query(self, query):
188-
"""Construct a job for running a SQL query synchronously.
188+
"""Run a SQL query synchronously.
189189
190190
:type query: string
191191
:param query: SQL query to be executed
192192
193-
:rtype: :class:`gcloud.bigquery.job.RunSyncQueryJob`
194-
:returns: a new ``RunSyncQueryJob`` instance
193+
:rtype: :class:`gcloud.bigquery.query.QueryResults`
194+
:returns: a new ``QueryResults`` instance
195195
"""
196-
return RunSyncQueryJob(query, client=self)
196+
return QueryResults(query, client=self)

0 commit comments

Comments
 (0)