1# Copyright 2015 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Classes for copy jobs."""
16
17import typing
18from typing import Optional
19
20from google.cloud.bigquery.encryption_configuration import EncryptionConfiguration
21from google.cloud.bigquery import _helpers
22from google.cloud.bigquery.table import TableReference
23
24from google.cloud.bigquery.job.base import _AsyncJob
25from google.cloud.bigquery.job.base import _JobConfig
26from google.cloud.bigquery.job.base import _JobReference
27
28
29class OperationType:
30 """Different operation types supported in table copy job.
31
32 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#operationtype
33 """
34
35 OPERATION_TYPE_UNSPECIFIED = "OPERATION_TYPE_UNSPECIFIED"
36 """Unspecified operation type."""
37
38 COPY = "COPY"
39 """The source and destination table have the same table type."""
40
41 SNAPSHOT = "SNAPSHOT"
42 """The source table type is TABLE and the destination table type is SNAPSHOT."""
43
44 CLONE = "CLONE"
45 """The source table type is TABLE and the destination table type is CLONE."""
46
47 RESTORE = "RESTORE"
48 """The source table type is SNAPSHOT and the destination table type is TABLE."""
49
50
51class CopyJobConfig(_JobConfig):
52 """Configuration options for copy jobs.
53
54 All properties in this class are optional. Values which are :data:`None` ->
55 server defaults. Set properties on the constructed configuration by using
56 the property name as the name of a keyword argument.
57 """
58
59 def __init__(self, **kwargs) -> None:
60 super(CopyJobConfig, self).__init__("copy", **kwargs)
61
62 @property
63 def create_disposition(self):
64 """google.cloud.bigquery.job.CreateDisposition: Specifies behavior
65 for creating tables.
66
67 See
68 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationTableCopy.FIELDS.create_disposition
69 """
70 return self._get_sub_prop("createDisposition")
71
72 @create_disposition.setter
73 def create_disposition(self, value):
74 self._set_sub_prop("createDisposition", value)
75
76 @property
77 def write_disposition(self):
78 """google.cloud.bigquery.job.WriteDisposition: Action that occurs if
79 the destination table already exists.
80
81 See
82 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationTableCopy.FIELDS.write_disposition
83 """
84 return self._get_sub_prop("writeDisposition")
85
86 @write_disposition.setter
87 def write_disposition(self, value):
88 self._set_sub_prop("writeDisposition", value)
89
90 @property
91 def destination_encryption_configuration(self):
92 """google.cloud.bigquery.encryption_configuration.EncryptionConfiguration: Custom
93 encryption configuration for the destination table.
94
95 Custom encryption configuration (e.g., Cloud KMS keys) or :data:`None`
96 if using default encryption.
97
98 See
99 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationTableCopy.FIELDS.destination_encryption_configuration
100 """
101 prop = self._get_sub_prop("destinationEncryptionConfiguration")
102 if prop is not None:
103 prop = EncryptionConfiguration.from_api_repr(prop)
104 return prop
105
106 @destination_encryption_configuration.setter
107 def destination_encryption_configuration(self, value):
108 api_repr = value
109 if value is not None:
110 api_repr = value.to_api_repr()
111 self._set_sub_prop("destinationEncryptionConfiguration", api_repr)
112
113 @property
114 def operation_type(self) -> str:
115 """The operation to perform with this copy job.
116
117 See
118 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationTableCopy.FIELDS.operation_type
119 """
120 return self._get_sub_prop(
121 "operationType", OperationType.OPERATION_TYPE_UNSPECIFIED
122 )
123
124 @operation_type.setter
125 def operation_type(self, value: Optional[str]):
126 if value is None:
127 value = OperationType.OPERATION_TYPE_UNSPECIFIED
128 self._set_sub_prop("operationType", value)
129
130 @property
131 def destination_expiration_time(self) -> str:
132 """google.cloud.bigquery.job.DestinationExpirationTime: The time when the
133 destination table expires. Expired tables will be deleted and their storage reclaimed.
134
135 See
136 https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationTableCopy.FIELDS.destination_expiration_time
137 """
138 return self._get_sub_prop("destinationExpirationTime")
139
140 @destination_expiration_time.setter
141 def destination_expiration_time(self, value: str):
142 self._set_sub_prop("destinationExpirationTime", value)
143
144
145class CopyJob(_AsyncJob):
146 """Asynchronous job: copy data into a table from other tables.
147
148 Args:
149 job_id (str): the job's ID, within the project belonging to ``client``.
150
151 sources (List[google.cloud.bigquery.table.TableReference]): Table from which data is to be loaded.
152
153 destination (google.cloud.bigquery.table.TableReference): Table into which data is to be loaded.
154
155 client (google.cloud.bigquery.client.Client):
156 A client which holds credentials and project configuration
157 for the dataset (which requires a project).
158
159 job_config (Optional[google.cloud.bigquery.job.CopyJobConfig]):
160 Extra configuration options for the copy job.
161 """
162
163 _JOB_TYPE = "copy"
164 _CONFIG_CLASS = CopyJobConfig
165
166 def __init__(self, job_id, sources, destination, client, job_config=None):
167 super(CopyJob, self).__init__(job_id, client)
168
169 if job_config is not None:
170 self._properties["configuration"] = job_config._properties
171
172 if destination:
173 _helpers._set_sub_prop(
174 self._properties,
175 ["configuration", "copy", "destinationTable"],
176 destination.to_api_repr(),
177 )
178
179 if sources:
180 source_resources = [source.to_api_repr() for source in sources]
181 _helpers._set_sub_prop(
182 self._properties,
183 ["configuration", "copy", "sourceTables"],
184 source_resources,
185 )
186
187 @property
188 def configuration(self) -> CopyJobConfig:
189 """The configuration for this copy job."""
190 return typing.cast(CopyJobConfig, super().configuration)
191
192 @property
193 def destination(self):
194 """google.cloud.bigquery.table.TableReference: Table into which data
195 is to be loaded.
196 """
197 return TableReference.from_api_repr(
198 _helpers._get_sub_prop(
199 self._properties, ["configuration", "copy", "destinationTable"]
200 )
201 )
202
203 @property
204 def sources(self):
205 """List[google.cloud.bigquery.table.TableReference]): Table(s) from
206 which data is to be loaded.
207 """
208 source_configs = _helpers._get_sub_prop(
209 self._properties, ["configuration", "copy", "sourceTables"]
210 )
211 if source_configs is None:
212 single = _helpers._get_sub_prop(
213 self._properties, ["configuration", "copy", "sourceTable"]
214 )
215 if single is None:
216 raise KeyError("Resource missing 'sourceTables' / 'sourceTable'")
217 source_configs = [single]
218
219 sources = []
220 for source_config in source_configs:
221 table_ref = TableReference.from_api_repr(source_config)
222 sources.append(table_ref)
223 return sources
224
225 @property
226 def create_disposition(self):
227 """See
228 :attr:`google.cloud.bigquery.job.CopyJobConfig.create_disposition`.
229 """
230 return self.configuration.create_disposition
231
232 @property
233 def write_disposition(self):
234 """See
235 :attr:`google.cloud.bigquery.job.CopyJobConfig.write_disposition`.
236 """
237 return self.configuration.write_disposition
238
239 @property
240 def destination_encryption_configuration(self):
241 """google.cloud.bigquery.encryption_configuration.EncryptionConfiguration: Custom
242 encryption configuration for the destination table.
243
244 Custom encryption configuration (e.g., Cloud KMS keys) or :data:`None`
245 if using default encryption.
246
247 See
248 :attr:`google.cloud.bigquery.job.CopyJobConfig.destination_encryption_configuration`.
249 """
250 return self.configuration.destination_encryption_configuration
251
252 def to_api_repr(self):
253 """Generate a resource for :meth:`_begin`."""
254 # Exclude statistics, if set.
255 return {
256 "jobReference": self._properties["jobReference"],
257 "configuration": self._properties["configuration"],
258 }
259
260 @classmethod
261 def from_api_repr(cls, resource, client):
262 """Factory: construct a job given its API representation
263
264 .. note::
265
266 This method assumes that the project found in the resource matches
267 the client's project.
268
269 Args:
270 resource (Dict): dataset job representation returned from the API
271 client (google.cloud.bigquery.client.Client):
272 Client which holds credentials and project
273 configuration for the dataset.
274
275 Returns:
276 google.cloud.bigquery.job.CopyJob: Job parsed from ``resource``.
277 """
278 cls._check_resource_config(resource)
279 job_ref = _JobReference._from_api_repr(resource["jobReference"])
280 job = cls(job_ref, None, None, client=client)
281 job._set_properties(resource)
282 return job