1818
1919import six
2020
21+ from gcloud .exceptions import NotFound
2122from gcloud .bigquery ._helpers import _datetime_from_prop
2223from gcloud .bigquery ._helpers import _prop_from_datetime
2324
2425
26+ _MARKER = object ()
27+
28+
2529class SchemaField (object ):
2630 """Describe a single field within a table schema.
2731
@@ -281,7 +285,7 @@ def view_query(self, value):
281285 """Update SQL query defining the table as a view.
282286
283287 :type value: string
284- :param value: new location
288+ :param value: new query
285289
286290 :raises: ValueError for invalid value types.
287291 """
@@ -293,3 +297,231 @@ def view_query(self, value):
293297 def view_query (self ):
294298 """Delete SQL query defining the table as a view."""
295299 self ._properties .pop ('view' , None )
300+
301+ def _require_client (self , client ):
302+ """Check client or verify over-ride.
303+
304+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
305+ :param client: the client to use. If not passed, falls back to the
306+ ``client`` stored on the current dataset.
307+
308+ :rtype: :class:`gcloud.bigquery.client.Client`
309+ :returns: The client passed in or the currently bound client.
310+ """
311+ if client is None :
312+ client = self ._dataset ._client
313+ return client
314+
315+ def _set_properties (self , api_response ):
316+ """Update properties from resource in body of ``api_response``
317+
318+ :type api_response: httplib2.Response
319+ :param api_response: response returned from an API call
320+ """
321+ self ._properties .clear ()
322+ cleaned = api_response .copy ()
323+ if 'creationTime' in cleaned :
324+ cleaned ['creationTime' ] = float (cleaned ['creationTime' ])
325+ if 'lastModifiedTime' in cleaned :
326+ cleaned ['lastModifiedTime' ] = float (cleaned ['lastModifiedTime' ])
327+ if 'expirationTime' in cleaned :
328+ cleaned ['expirationTime' ] = float (cleaned ['expirationTime' ])
329+ self ._properties .update (cleaned )
330+
331+ def _build_schema_resource (self , fields = None ):
332+ """Generate a resource fragment for table's schema."""
333+ if fields is None :
334+ fields = self ._schema
335+ infos = []
336+ for field in fields :
337+ info = {'name' : field .name ,
338+ 'type' : field .field_type ,
339+ 'mode' : field .mode }
340+ if field .description is not None :
341+ info ['description' ] = field .description
342+ if field .fields is not None :
343+ info ['fields' ] = self ._build_schema_resource (field .fields )
344+ infos .append (info )
345+ return infos
346+
347+ def _build_resource (self ):
348+ """Generate a resource for ``create`` or ``update``."""
349+ resource = {
350+ 'tableReference' : {
351+ 'projectId' : self ._dataset .project ,
352+ 'datasetId' : self ._dataset .name ,
353+ 'tableId' : self .name },
354+ 'schema' : {'fields' : self ._build_schema_resource ()},
355+ }
356+ if self .description is not None :
357+ resource ['description' ] = self .description
358+
359+ if self .expires is not None :
360+ value = _prop_from_datetime (self .expires )
361+ resource ['expirationTime' ] = value
362+
363+ if self .friendly_name is not None :
364+ resource ['friendlyName' ] = self .friendly_name
365+
366+ if self .location is not None :
367+ resource ['location' ] = self .location
368+
369+ if self .view_query is not None :
370+ view = resource ['view' ] = {}
371+ view ['query' ] = self .view_query
372+
373+ return resource
374+
375+ def create (self , client = None ):
376+ """API call: create the dataset via a PUT request
377+
378+ See:
379+ https://cloud.google.com/bigquery/reference/rest/v2/tables/insert
380+
381+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
382+ :param client: the client to use. If not passed, falls back to the
383+ ``client`` stored on the current dataset.
384+ """
385+ client = self ._require_client (client )
386+ path = '/projects/%s/datasets/%s/tables' % (
387+ self ._dataset .project , self ._dataset .name )
388+ api_response = client .connection .api_request (
389+ method = 'POST' , path = path , data = self ._build_resource ())
390+ self ._set_properties (api_response )
391+
392+ def exists (self , client = None ):
393+ """API call: test for the existence of the table via a GET request
394+
395+ See
396+ https://cloud.google.com/bigquery/docs/reference/v2/tables/get
397+
398+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
399+ :param client: the client to use. If not passed, falls back to the
400+ ``client`` stored on the current dataset.
401+ """
402+ client = self ._require_client (client )
403+
404+ try :
405+ client .connection .api_request (method = 'GET' , path = self .path ,
406+ query_params = {'fields' : 'id' })
407+ except NotFound :
408+ return False
409+ else :
410+ return True
411+
412+ def reload (self , client = None ):
413+ """API call: refresh table properties via a GET request
414+
415+ See
416+ https://cloud.google.com/bigquery/docs/reference/v2/tables/get
417+
418+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
419+ :param client: the client to use. If not passed, falls back to the
420+ ``client`` stored on the current dataset.
421+ """
422+ client = self ._require_client (client )
423+
424+ api_response = client .connection .api_request (
425+ method = 'GET' , path = self .path )
426+ self ._set_properties (api_response )
427+
428+ def patch (self ,
429+ client = None ,
430+ friendly_name = _MARKER ,
431+ description = _MARKER ,
432+ location = _MARKER ,
433+ expires = _MARKER ,
434+ view_query = _MARKER ,
435+ schema = _MARKER ):
436+ """API call: update individual table properties via a PATCH request
437+
438+ See
439+ https://cloud.google.com/bigquery/docs/reference/v2/tables/patch
440+
441+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
442+ :param client: the client to use. If not passed, falls back to the
443+ ``client`` stored on the current dataset.
444+
445+ :type friendly_name: string or ``NoneType``
446+ :param friendly_name: point in time at which the table expires.
447+
448+ :type description: string or ``NoneType``
449+ :param description: point in time at which the table expires.
450+
451+ :type location: string or ``NoneType``
452+ :param location: point in time at which the table expires.
453+
454+ :type expires: :class:`datetime.datetime` or ``NoneType``
455+ :param expires: point in time at which the table expires.
456+
457+ :type view_query: string
458+ :param view_query: SQL query defining the table as a view
459+
460+ :type schema: list of :class:`SchemaField`
461+ :param schema: fields describing the schema
462+
463+ :raises: ValueError for invalid value types.
464+ """
465+ client = self ._require_client (client )
466+
467+ partial = {}
468+
469+ if expires is not _MARKER :
470+ if (not isinstance (expires , datetime .datetime ) and
471+ expires is not None ):
472+ raise ValueError ("Pass a datetime, or None" )
473+ partial ['expirationTime' ] = _prop_from_datetime (expires )
474+
475+ if description is not _MARKER :
476+ partial ['description' ] = description
477+
478+ if friendly_name is not _MARKER :
479+ partial ['friendlyName' ] = friendly_name
480+
481+ if location is not _MARKER :
482+ partial ['location' ] = location
483+
484+ if view_query is not _MARKER :
485+ if view_query is None :
486+ partial ['view' ] = None
487+ else :
488+ partial ['view' ] = {'query' : view_query }
489+
490+ if schema is not _MARKER :
491+ if schema is None :
492+ partial ['schema' ] = None
493+ else :
494+ partial ['schema' ] = {
495+ 'fields' : self ._build_schema_resource (schema )}
496+
497+ api_response = client .connection .api_request (
498+ method = 'PATCH' , path = self .path , data = partial )
499+ self ._set_properties (api_response )
500+
501+ def update (self , client = None ):
502+ """API call: update table properties via a PUT request
503+
504+ See
505+ https://cloud.google.com/bigquery/docs/reference/v2/tables/update
506+
507+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
508+ :param client: the client to use. If not passed, falls back to the
509+ ``client`` stored on the current dataset.
510+ """
511+ client = self ._require_client (client )
512+ api_response = client .connection .api_request (
513+ method = 'PUT' , path = self .path , data = self ._build_resource ())
514+ self ._set_properties (api_response )
515+
516+ def delete (self , client = None ):
517+ """API call: delete the table via a DELETE request
518+
519+ See:
520+ https://cloud.google.com/bigquery/reference/rest/v2/tables/delete
521+
522+ :type client: :class:`gcloud.bigquery.client.Client` or ``NoneType``
523+ :param client: the client to use. If not passed, falls back to the
524+ ``client`` stored on the current dataset.
525+ """
526+ client = self ._require_client (client )
527+ client .connection .api_request (method = 'DELETE' , path = self .path )
0 commit comments