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
2 changes: 2 additions & 0 deletions bigquery/google/cloud/bigquery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from google.cloud.bigquery.job import QueryJob
from google.cloud.bigquery.job import QueryJobConfig
from google.cloud.bigquery.job import QueryPriority
from google.cloud.bigquery.job import SchemaUpdateOption
from google.cloud.bigquery.job import SourceFormat
from google.cloud.bigquery.job import UnknownJob
from google.cloud.bigquery.job import WriteDisposition
Expand Down Expand Up @@ -113,6 +114,7 @@
'DestinationFormat',
'Encoding',
'QueryPriority',
'SchemaUpdateOption',
'SourceFormat',
'WriteDisposition'
]
Expand Down
50 changes: 50 additions & 0 deletions bigquery/google/cloud/bigquery/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@ class WriteDisposition(object):
returned in the job result."""


class SchemaUpdateOption(object):
"""Specifies an update to the destination table schema as a side effect of
a load job.
"""

ALLOW_FIELD_ADDITION = 'ALLOW_FIELD_ADDITION'
"""Allow adding a nullable field to the schema."""

ALLOW_FIELD_RELAXATION = 'ALLOW_FIELD_RELAXATION'
"""Allow relaxing a required field in the original schema to nullable."""


class _JobReference(object):
"""A reference to a job.

Expand Down Expand Up @@ -1004,6 +1016,18 @@ def time_partitioning(self, value):
api_repr = value.to_api_repr()
self._set_sub_prop('timePartitioning', api_repr)

@property
def schema_update_options(self):
"""List[google.cloud.bigquery.job.SchemaUpdateOption]: Specifies
updates to the destination table schema to allow as a side effect of
the load job.
"""
return self._get_sub_prop('schemaUpdateOptions')

@schema_update_options.setter
def schema_update_options(self, values):
self._set_sub_prop('schemaUpdateOptions', values)


class LoadJob(_AsyncJob):
"""Asynchronous job for loading data into a table.
Expand Down Expand Up @@ -1158,6 +1182,13 @@ def time_partitioning(self):
"""
return self._configuration.time_partitioning

@property
def schema_update_options(self):
"""See
:attr:`google.cloud.bigquery.job.LoadJobConfig.schema_update_options`.
"""
return self._configuration.schema_update_options

@property
def input_file_bytes(self):
"""Count of bytes loaded from source files.
Expand Down Expand Up @@ -1971,6 +2002,18 @@ def time_partitioning(self, value):
api_repr = value.to_api_repr()
self._set_sub_prop('timePartitioning', api_repr)

@property
def schema_update_options(self):
"""List[google.cloud.bigquery.job.SchemaUpdateOption]: Specifies
updates to the destination table schema to allow as a side effect of
the query job.
"""
return self._get_sub_prop('schemaUpdateOptions')

@schema_update_options.setter
def schema_update_options(self, values):
self._set_sub_prop('schemaUpdateOptions', values)

def to_api_repr(self):
"""Build an API representation of the query job config.

Expand Down Expand Up @@ -2149,6 +2192,13 @@ def time_partitioning(self):
"""
return self._configuration.time_partitioning

@property
def schema_update_options(self):
"""See
:attr:`google.cloud.bigquery.job.QueryJobConfig.schema_update_options`.
"""
return self._configuration.schema_update_options

def _build_resource(self):
"""Generate a resource for :meth:`begin`."""
configuration = self._configuration.to_api_repr()
Expand Down
34 changes: 32 additions & 2 deletions bigquery/tests/unit/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ def _verifyEnumConfigProperties(self, job, config):
config['writeDisposition'])
else:
self.assertIsNone(job.write_disposition)
if 'schemaUpdateOptions' in config:
self.assertEqual(
job.schema_update_options, config['schemaUpdateOptions'])
else:
self.assertIsNone(job.schema_update_options)

def _verifyResourceProperties(self, job, resource):
self._verifyReadonlyResourceProperties(job, resource)
Expand Down Expand Up @@ -467,6 +472,7 @@ def test_ctor(self):
self.assertIsNone(job.write_disposition)
self.assertIsNone(job.destination_encryption_configuration)
self.assertIsNone(job.time_partitioning)
self.assertIsNone(job.schema_update_options)

def test_ctor_w_config(self):
from google.cloud.bigquery.schema import SchemaField
Expand Down Expand Up @@ -780,6 +786,7 @@ def test_begin_w_autodetect(self):

def test_begin_w_alternate_client(self):
from google.cloud.bigquery.job import CreateDisposition
from google.cloud.bigquery.job import SchemaUpdateOption
from google.cloud.bigquery.job import WriteDisposition
from google.cloud.bigquery.schema import SchemaField

Expand Down Expand Up @@ -817,7 +824,10 @@ def test_begin_w_alternate_client(self):
'mode': 'REQUIRED',
'description': None,
},
]}
]},
'schemaUpdateOptions': [
SchemaUpdateOption.ALLOW_FIELD_ADDITION,
],
}
RESOURCE['configuration']['load'] = LOAD_CONFIGURATION
conn1 = _make_connection()
Expand All @@ -842,6 +852,9 @@ def test_begin_w_alternate_client(self):
config.skip_leading_rows = 1
config.source_format = 'CSV'
config.write_disposition = WriteDisposition.WRITE_TRUNCATE
config.schema_update_options = [
SchemaUpdateOption.ALLOW_FIELD_ADDITION,
]

job._begin(client=client2)

Expand Down Expand Up @@ -2127,6 +2140,11 @@ def _verifyResourceProperties(self, job, resource):
'kmsKeyName'])
else:
self.assertIsNone(job.destination_encryption_configuration)
if 'schemaUpdateOptions' in query_config:
self.assertEqual(
job.schema_update_options, query_config['schemaUpdateOptions'])
else:
self.assertIsNone(job.schema_update_options)

def test_ctor_defaults(self):
client = _make_client(project=self.PROJECT)
Expand Down Expand Up @@ -2157,6 +2175,7 @@ def test_ctor_defaults(self):
self.assertIsNone(job.table_definitions)
self.assertIsNone(job.destination_encryption_configuration)
self.assertIsNone(job.time_partitioning)
self.assertIsNone(job.schema_update_options)

def test_ctor_w_udf_resources(self):
from google.cloud.bigquery.job import QueryJobConfig
Expand Down Expand Up @@ -2248,6 +2267,7 @@ def test_from_api_repr_with_encryption(self):

def test_from_api_repr_w_properties(self):
from google.cloud.bigquery.job import CreateDisposition
from google.cloud.bigquery.job import SchemaUpdateOption
from google.cloud.bigquery.job import WriteDisposition

client = _make_client(project=self.PROJECT)
Expand All @@ -2260,6 +2280,9 @@ def test_from_api_repr_w_properties(self):
'datasetId': self.DS_ID,
'tableId': self.DESTINATION_TABLE,
}
query_config['schemaUpdateOptions'] = [
SchemaUpdateOption.ALLOW_FIELD_ADDITION,
]
klass = self._get_target_class()
job = klass.from_api_repr(RESOURCE, client=client)
self.assertIs(job._client, client)
Expand Down Expand Up @@ -2841,6 +2864,7 @@ def test_begin_w_alternate_client(self):
from google.cloud.bigquery.job import CreateDisposition
from google.cloud.bigquery.job import QueryJobConfig
from google.cloud.bigquery.job import QueryPriority
from google.cloud.bigquery.job import SchemaUpdateOption
from google.cloud.bigquery.job import WriteDisposition

PATH = '/projects/%s/jobs' % (self.PROJECT,)
Expand All @@ -2866,7 +2890,10 @@ def test_begin_w_alternate_client(self):
'useLegacySql': True,
'writeDisposition': WriteDisposition.WRITE_TRUNCATE,
'maximumBillingTier': 4,
'maximumBytesBilled': '123456'
'maximumBytesBilled': '123456',
'schemaUpdateOptions': [
SchemaUpdateOption.ALLOW_FIELD_RELAXATION,
]
}
RESOURCE['configuration']['query'] = QUERY_CONFIGURATION
RESOURCE['configuration']['dryRun'] = True
Expand All @@ -2890,6 +2917,9 @@ def test_begin_w_alternate_client(self):
config.use_query_cache = True
config.write_disposition = WriteDisposition.WRITE_TRUNCATE
config.maximum_bytes_billed = 123456
config.schema_update_options = [
SchemaUpdateOption.ALLOW_FIELD_RELAXATION,
]
job = self._make_one(
self.JOB_ID, self.QUERY, client1, job_config=config)

Expand Down
1 change: 1 addition & 0 deletions docs/bigquery/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Job-Related Types
job.QueryPriority
job.SourceFormat
job.WriteDisposition
job.SchemaUpdateOption


Dataset
Expand Down
Loading