google-cloud-bigquery 1.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +16 -0
  3. data/AUTHENTICATION.md +158 -0
  4. data/CHANGELOG.md +397 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +188 -0
  7. data/LICENSE +201 -0
  8. data/LOGGING.md +27 -0
  9. data/OVERVIEW.md +463 -0
  10. data/TROUBLESHOOTING.md +31 -0
  11. data/lib/google-cloud-bigquery.rb +139 -0
  12. data/lib/google/cloud/bigquery.rb +145 -0
  13. data/lib/google/cloud/bigquery/argument.rb +197 -0
  14. data/lib/google/cloud/bigquery/convert.rb +383 -0
  15. data/lib/google/cloud/bigquery/copy_job.rb +316 -0
  16. data/lib/google/cloud/bigquery/credentials.rb +50 -0
  17. data/lib/google/cloud/bigquery/data.rb +526 -0
  18. data/lib/google/cloud/bigquery/dataset.rb +2845 -0
  19. data/lib/google/cloud/bigquery/dataset/access.rb +1021 -0
  20. data/lib/google/cloud/bigquery/dataset/list.rb +162 -0
  21. data/lib/google/cloud/bigquery/encryption_configuration.rb +123 -0
  22. data/lib/google/cloud/bigquery/external.rb +2432 -0
  23. data/lib/google/cloud/bigquery/extract_job.rb +368 -0
  24. data/lib/google/cloud/bigquery/insert_response.rb +180 -0
  25. data/lib/google/cloud/bigquery/job.rb +657 -0
  26. data/lib/google/cloud/bigquery/job/list.rb +162 -0
  27. data/lib/google/cloud/bigquery/load_job.rb +1704 -0
  28. data/lib/google/cloud/bigquery/model.rb +740 -0
  29. data/lib/google/cloud/bigquery/model/list.rb +164 -0
  30. data/lib/google/cloud/bigquery/project.rb +1655 -0
  31. data/lib/google/cloud/bigquery/project/list.rb +161 -0
  32. data/lib/google/cloud/bigquery/query_job.rb +1695 -0
  33. data/lib/google/cloud/bigquery/routine.rb +1108 -0
  34. data/lib/google/cloud/bigquery/routine/list.rb +165 -0
  35. data/lib/google/cloud/bigquery/schema.rb +564 -0
  36. data/lib/google/cloud/bigquery/schema/field.rb +668 -0
  37. data/lib/google/cloud/bigquery/service.rb +589 -0
  38. data/lib/google/cloud/bigquery/standard_sql.rb +495 -0
  39. data/lib/google/cloud/bigquery/table.rb +3340 -0
  40. data/lib/google/cloud/bigquery/table/async_inserter.rb +520 -0
  41. data/lib/google/cloud/bigquery/table/list.rb +172 -0
  42. data/lib/google/cloud/bigquery/time.rb +65 -0
  43. data/lib/google/cloud/bigquery/version.rb +22 -0
  44. metadata +297 -0
@@ -0,0 +1,383 @@
1
+ # Copyright 2017 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
+ # https://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
+
16
+ require "google/apis/bigquery_v2"
17
+ require "stringio"
18
+ require "base64"
19
+ require "bigdecimal"
20
+ require "time"
21
+ require "date"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Bigquery
26
+ # rubocop:disable Metrics/ModuleLength
27
+
28
+ ##
29
+ # @private
30
+ #
31
+ # Internal conversion of raw data values to/from Bigquery values
32
+ #
33
+ # | BigQuery | Ruby | Notes |
34
+ # |-------------|----------------|---|
35
+ # | `BOOL` | `true`/`false` | |
36
+ # | `INT64` | `Integer` | |
37
+ # | `FLOAT64` | `Float` | |
38
+ # | `NUMERIC` | `BigDecimal` | Will be rounded to 9 decimal places |
39
+ # | `STRING` | `String` | |
40
+ # | `DATETIME` | `DateTime` | `DATETIME` does not support time zone. |
41
+ # | `DATE` | `Date` | |
42
+ # | `TIMESTAMP` | `Time` | |
43
+ # | `TIME` | `Google::Cloud::BigQuery::Time` | |
44
+ # | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
45
+ # | `ARRAY` | `Array` | Nested arrays, `nil` values are not supported. |
46
+ # | `STRUCT` | `Hash` | Hash keys may be strings or symbols. |
47
+ module Convert
48
+ ##
49
+ # @private
50
+ def self.format_rows rows, fields
51
+ Array(rows).map do |row|
52
+ # convert TableRow to hash to handle nested TableCell values
53
+ format_row row.to_h, fields
54
+ end
55
+ end
56
+
57
+ ##
58
+ # @private
59
+ def self.format_row row, fields
60
+ row_pairs = fields.zip(row[:f]).map do |f, v|
61
+ [f.name.to_sym, format_value(v, f)]
62
+ end
63
+ Hash[row_pairs]
64
+ end
65
+
66
+ # rubocop:disable all
67
+
68
+ def self.format_value value, field
69
+ if value.nil?
70
+ nil
71
+ elsif value.empty?
72
+ nil
73
+ elsif value[:v].nil?
74
+ nil
75
+ elsif Array === value[:v]
76
+ value[:v].map { |v| format_value v, field }
77
+ elsif Hash === value[:v]
78
+ format_row value[:v], field.fields
79
+ elsif field.type == "STRING"
80
+ String value[:v]
81
+ elsif field.type == "INTEGER"
82
+ Integer value[:v]
83
+ elsif field.type == "FLOAT"
84
+ if value[:v] == "Infinity"
85
+ Float::INFINITY
86
+ elsif value[:v] == "-Infinity"
87
+ -Float::INFINITY
88
+ elsif value[:v] == "NaN"
89
+ Float::NAN
90
+ else
91
+ Float value[:v]
92
+ end
93
+ elsif field.type == "NUMERIC"
94
+ BigDecimal value[:v]
95
+ elsif field.type == "BOOLEAN"
96
+ (value[:v] == "true" ? true : (value[:v] == "false" ? false : nil))
97
+ elsif field.type == "BYTES"
98
+ StringIO.new Base64.decode64 value[:v]
99
+ elsif field.type == "TIMESTAMP"
100
+ ::Time.at Float(value[:v])
101
+ elsif field.type == "TIME"
102
+ Bigquery::Time.new value[:v]
103
+ elsif field.type == "DATETIME"
104
+ ::Time.parse("#{value[:v]} UTC").to_datetime
105
+ elsif field.type == "DATE"
106
+ Date.parse value[:v]
107
+ else
108
+ value[:v]
109
+ end
110
+ end
111
+
112
+ ##
113
+ # @private
114
+ def self.to_query_param param, type = nil
115
+ type ||= default_query_param_type_for param
116
+
117
+ Google::Apis::BigqueryV2::QueryParameter.new(
118
+ parameter_type: to_query_param_type(type),
119
+ parameter_value: to_query_param_value(param)
120
+ )
121
+ end
122
+
123
+ ##
124
+ # @private
125
+ def self.to_query_param_value value
126
+ return Google::Apis::BigqueryV2::QueryParameterValue.new value: nil if value.nil?
127
+
128
+ json_value = to_json_value value
129
+
130
+ if Array === json_value
131
+ array_values = json_value.map { |v| to_query_param_value v }
132
+ Google::Apis::BigqueryV2::QueryParameterValue.new array_values: array_values
133
+ elsif Hash === json_value
134
+ struct_pairs = json_value.map do |key, value|
135
+ [String(key), to_query_param_value(value)]
136
+ end
137
+ struct_values = Hash[struct_pairs]
138
+ Google::Apis::BigqueryV2::QueryParameterValue.new struct_values: struct_values
139
+ else
140
+ # Everything else is converted to a string, per the API expectations.
141
+ Google::Apis::BigqueryV2::QueryParameterValue.new value: json_value.to_s
142
+ end
143
+ end
144
+
145
+ def self.to_query_param_type type
146
+ if Array === type
147
+ Google::Apis::BigqueryV2::QueryParameterType.new(
148
+ type: "ARRAY".freeze,
149
+ array_type: to_query_param_type(type.first)
150
+ )
151
+ elsif Hash === type
152
+ Google::Apis::BigqueryV2::QueryParameterType.new(
153
+ type: "STRUCT".freeze,
154
+ struct_types: type.map do |key, val|
155
+ Google::Apis::BigqueryV2::QueryParameterType::StructType.new(
156
+ name: String(key),
157
+ type: to_query_param_type(val)
158
+ )
159
+ end
160
+ )
161
+ else
162
+ Google::Apis::BigqueryV2::QueryParameterType.new(type: type.to_s.freeze)
163
+ end
164
+ end
165
+
166
+ def self.default_query_param_type_for param
167
+ raise ArgumentError, "nil params are not supported, must assign optional type" if param.nil?
168
+
169
+ case param
170
+ when String
171
+ :STRING
172
+ when Symbol
173
+ :STRING
174
+ when TrueClass
175
+ :BOOL
176
+ when FalseClass
177
+ :BOOL
178
+ when Integer
179
+ :INT64
180
+ when BigDecimal
181
+ :NUMERIC
182
+ when Numeric
183
+ :FLOAT64
184
+ when ::Time
185
+ :TIMESTAMP
186
+ when Bigquery::Time
187
+ :TIME
188
+ when DateTime
189
+ :DATETIME
190
+ when Date
191
+ :DATE
192
+ when Array
193
+ if param.empty?
194
+ raise ArgumentError, "Cannot determine type for empty array values"
195
+ end
196
+ non_nil_values = param.compact.map { |p| default_query_param_type_for p }.compact
197
+ if non_nil_values.empty?
198
+ raise ArgumentError, "Cannot determine type for array of nil values"
199
+ end
200
+ if non_nil_values.uniq.count > 1
201
+ raise ArgumentError, "Cannot determine type for array of different types of values"
202
+ end
203
+ [non_nil_values.first]
204
+ when Hash
205
+ Hash[param.map do |key, value|
206
+ [key, default_query_param_type_for(value)]
207
+ end]
208
+ else
209
+ if param.respond_to?(:read) && param.respond_to?(:rewind)
210
+ :BYTES
211
+ else
212
+ raise "A query parameter of type #{param.class} is not supported"
213
+ end
214
+ end
215
+ end
216
+
217
+ ##
218
+ # @private
219
+ def self.to_json_value value
220
+ if DateTime === value
221
+ value.strftime "%Y-%m-%d %H:%M:%S.%6N"
222
+ elsif Date === value
223
+ value.to_s
224
+ elsif ::Time === value
225
+ value.strftime "%Y-%m-%d %H:%M:%S.%6N%:z"
226
+ elsif Bigquery::Time === value
227
+ value.value
228
+ elsif BigDecimal === value
229
+ # Round to precision of 9
230
+ value.finite? ? value.round(9).to_s("F") : value.to_s
231
+ elsif value.respond_to?(:read) && value.respond_to?(:rewind)
232
+ value.rewind
233
+ Base64.strict_encode64(value.read.force_encoding("ASCII-8BIT"))
234
+ elsif Array === value
235
+ value.map { |v| to_json_value v }
236
+ elsif Hash === value
237
+ Hash[value.map { |k, v| [k.to_s, to_json_value(v)] }]
238
+ else
239
+ value
240
+ end
241
+ end
242
+
243
+ # rubocop:enable all
244
+
245
+ ##
246
+ # @private
247
+ def self.to_json_rows rows
248
+ rows.map { |row| to_json_row row }
249
+ end
250
+
251
+ ##
252
+ # @private
253
+ def self.to_json_row row
254
+ Hash[row.map { |k, v| [k.to_s, to_json_value(v)] }]
255
+ end
256
+
257
+ def self.resolve_legacy_sql standard_sql, legacy_sql
258
+ return !standard_sql unless standard_sql.nil?
259
+ return legacy_sql unless legacy_sql.nil?
260
+ false
261
+ end
262
+
263
+ ##
264
+ # @private
265
+ #
266
+ # Converts create disposition strings to API values.
267
+ #
268
+ # @return [String] API representation of create disposition.
269
+ def self.create_disposition str
270
+ val = {
271
+ "create_if_needed" => "CREATE_IF_NEEDED",
272
+ "createifneeded" => "CREATE_IF_NEEDED",
273
+ "if_needed" => "CREATE_IF_NEEDED",
274
+ "needed" => "CREATE_IF_NEEDED",
275
+ "create_never" => "CREATE_NEVER",
276
+ "createnever" => "CREATE_NEVER",
277
+ "never" => "CREATE_NEVER"
278
+ }[str.to_s.downcase]
279
+ return val unless val.nil?
280
+ str
281
+ end
282
+
283
+ ##
284
+ # @private
285
+ #
286
+ # Converts write disposition strings to API values.
287
+ #
288
+ # @return [String] API representation of write disposition.
289
+ def self.write_disposition str
290
+ val = {
291
+ "write_truncate" => "WRITE_TRUNCATE",
292
+ "writetruncate" => "WRITE_TRUNCATE",
293
+ "truncate" => "WRITE_TRUNCATE",
294
+ "write_append" => "WRITE_APPEND",
295
+ "writeappend" => "WRITE_APPEND",
296
+ "append" => "WRITE_APPEND",
297
+ "write_empty" => "WRITE_EMPTY",
298
+ "writeempty" => "WRITE_EMPTY",
299
+ "empty" => "WRITE_EMPTY"
300
+ }[str.to_s.downcase]
301
+ return val unless val.nil?
302
+ str
303
+ end
304
+
305
+ ##
306
+ # @private
307
+ #
308
+ # Converts source format strings to API values.
309
+ #
310
+ # @return [String] API representation of source format.
311
+ def self.source_format format
312
+ val = {
313
+ "csv" => "CSV",
314
+ "json" => "NEWLINE_DELIMITED_JSON",
315
+ "newline_delimited_json" => "NEWLINE_DELIMITED_JSON",
316
+ "avro" => "AVRO",
317
+ "orc" => "ORC",
318
+ "parquet" => "PARQUET",
319
+ "datastore" => "DATASTORE_BACKUP",
320
+ "backup" => "DATASTORE_BACKUP",
321
+ "datastore_backup" => "DATASTORE_BACKUP"
322
+ }[format.to_s.downcase]
323
+ return val unless val.nil?
324
+ format
325
+ end
326
+
327
+ ##
328
+ # @private
329
+ #
330
+ # Converts file paths into source format by extension.
331
+ #
332
+ # @return [String] API representation of source format.
333
+ def self.derive_source_format_from_list paths
334
+ paths.map do |path|
335
+ derive_source_format path
336
+ end.compact.uniq.first
337
+ end
338
+
339
+ ##
340
+ # @private
341
+ #
342
+ # Converts file path into source format by extension.
343
+ #
344
+ # @return [String] API representation of source format.
345
+ def self.derive_source_format path
346
+ return "CSV" if path.end_with? ".csv"
347
+ return "NEWLINE_DELIMITED_JSON" if path.end_with? ".json"
348
+ return "AVRO" if path.end_with? ".avro"
349
+ return "ORC" if path.end_with? ".orc"
350
+ return "PARQUET" if path.end_with? ".parquet"
351
+ return "DATASTORE_BACKUP" if path.end_with? ".backup_info"
352
+ nil
353
+ end
354
+
355
+ ##
356
+ # @private
357
+ #
358
+ # Converts a primitive time value in milliseconds to a Ruby Time object.
359
+ #
360
+ # @return [Time, nil] The Ruby Time object, or nil if the given argument
361
+ # is nil.
362
+ def self.millis_to_time time_millis
363
+ return nil unless time_millis
364
+ ::Time.at Rational(time_millis, 1000)
365
+ end
366
+
367
+ ##
368
+ # @private
369
+ #
370
+ # Converts a Ruby Time object to a primitive time value in milliseconds.
371
+ #
372
+ # @return [Integer, nil] The primitive time value in milliseconds, or
373
+ # nil if the given argument is nil.
374
+ def self.time_to_millis time_obj
375
+ return nil unless time_obj
376
+ (time_obj.to_i * 1000) + (time_obj.nsec / 1_000_000)
377
+ end
378
+ end
379
+
380
+ # rubocop:enable Metrics/ModuleLength
381
+ end
382
+ end
383
+ end
@@ -0,0 +1,316 @@
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
+ # https://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
+ require "google/cloud/bigquery/encryption_configuration"
16
+
17
+ module Google
18
+ module Cloud
19
+ module Bigquery
20
+ ##
21
+ # # CopyJob
22
+ #
23
+ # A {Job} subclass representing a copy operation that may be performed on
24
+ # a {Table}. A CopyJob instance is created when you call {Table#copy_job}.
25
+ #
26
+ # @see https://cloud.google.com/bigquery/docs/tables#copy-table Copying
27
+ # an Existing Table
28
+ # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
29
+ # reference
30
+ #
31
+ # @example
32
+ # require "google/cloud/bigquery"
33
+ #
34
+ # bigquery = Google::Cloud::Bigquery.new
35
+ # dataset = bigquery.dataset "my_dataset"
36
+ # table = dataset.table "my_table"
37
+ # destination_table = dataset.table "my_destination_table"
38
+ #
39
+ # copy_job = table.copy_job destination_table
40
+ #
41
+ # copy_job.wait_until_done!
42
+ # copy_job.done? #=> true
43
+ #
44
+ class CopyJob < Job
45
+ ##
46
+ # The table from which data is copied. This is the table on
47
+ # which {Table#copy_job} was called.
48
+ #
49
+ # @return [Table] A table instance.
50
+ #
51
+ def source
52
+ table = @gapi.configuration.copy.source_table
53
+ return nil unless table
54
+ retrieve_table table.project_id, table.dataset_id, table.table_id
55
+ end
56
+
57
+ ##
58
+ # The table to which data is copied.
59
+ #
60
+ # @return [Table] A table instance.
61
+ #
62
+ def destination
63
+ table = @gapi.configuration.copy.destination_table
64
+ return nil unless table
65
+ retrieve_table table.project_id, table.dataset_id, table.table_id
66
+ end
67
+
68
+ ##
69
+ # Checks if the create disposition for the job is `CREATE_IF_NEEDED`,
70
+ # which provides the following behavior: If the table does not exist,
71
+ # the copy operation creates the table. This is the default create
72
+ # disposition for copy jobs.
73
+ #
74
+ # @return [Boolean] `true` when `CREATE_IF_NEEDED`, `false` otherwise.
75
+ #
76
+ def create_if_needed?
77
+ disp = @gapi.configuration.copy.create_disposition
78
+ disp == "CREATE_IF_NEEDED"
79
+ end
80
+
81
+ ##
82
+ # Checks if the create disposition for the job is `CREATE_NEVER`, which
83
+ # provides the following behavior: The table must already exist; if it
84
+ # does not, an error is returned in the job result.
85
+ #
86
+ # @return [Boolean] `true` when `CREATE_NEVER`, `false` otherwise.
87
+ #
88
+ def create_never?
89
+ disp = @gapi.configuration.copy.create_disposition
90
+ disp == "CREATE_NEVER"
91
+ end
92
+
93
+ ##
94
+ # Checks if the write disposition for the job is `WRITE_TRUNCATE`, which
95
+ # provides the following behavior: If the table already exists, the copy
96
+ # operation overwrites the table data.
97
+ #
98
+ # @return [Boolean] `true` when `WRITE_TRUNCATE`, `false` otherwise.
99
+ #
100
+ def write_truncate?
101
+ disp = @gapi.configuration.copy.write_disposition
102
+ disp == "WRITE_TRUNCATE"
103
+ end
104
+
105
+ ##
106
+ # Checks if the write disposition for the job is `WRITE_APPEND`, which
107
+ # provides the following behavior: If the table already exists, the copy
108
+ # operation appends the data to the table.
109
+ #
110
+ # @return [Boolean] `true` when `WRITE_APPEND`, `false` otherwise.
111
+ #
112
+ def write_append?
113
+ disp = @gapi.configuration.copy.write_disposition
114
+ disp == "WRITE_APPEND"
115
+ end
116
+
117
+ ##
118
+ # Checks if the write disposition for the job is `WRITE_EMPTY`, which
119
+ # provides the following behavior: If the table already exists and
120
+ # contains data, the job will have an error. This is the default write
121
+ # disposition for copy jobs.
122
+ #
123
+ # @return [Boolean] `true` when `WRITE_EMPTY`, `false` otherwise.
124
+ #
125
+ def write_empty?
126
+ disp = @gapi.configuration.copy.write_disposition
127
+ disp == "WRITE_EMPTY"
128
+ end
129
+
130
+ ##
131
+ # The encryption configuration of the destination table.
132
+ #
133
+ # @return [Google::Cloud::BigQuery::EncryptionConfiguration] Custom
134
+ # encryption configuration (e.g., Cloud KMS keys).
135
+ #
136
+ # @!group Attributes
137
+ def encryption
138
+ EncryptionConfiguration.from_gapi @gapi.configuration.copy.destination_encryption_configuration
139
+ end
140
+
141
+ ##
142
+ # Yielded to a block to accumulate changes for an API request.
143
+ class Updater < CopyJob
144
+ ##
145
+ # @private Create an Updater object.
146
+ def initialize gapi
147
+ @gapi = gapi
148
+ end
149
+
150
+ ##
151
+ # @private Create an Updater from an options hash.
152
+ #
153
+ # @return [Google::Cloud::Bigquery::CopyJob::Updater] A job
154
+ # configuration object for setting copy options.
155
+ def self.from_options service, source, target, options
156
+ job_ref = service.job_ref_from options[:job_id], options[:prefix]
157
+ copy_cfg = Google::Apis::BigqueryV2::JobConfigurationTableCopy.new(
158
+ source_table: source,
159
+ destination_table: target
160
+ )
161
+ req = Google::Apis::BigqueryV2::Job.new(
162
+ job_reference: job_ref,
163
+ configuration: Google::Apis::BigqueryV2::JobConfiguration.new(
164
+ copy: copy_cfg,
165
+ dry_run: options[:dryrun]
166
+ )
167
+ )
168
+
169
+ updater = CopyJob::Updater.new req
170
+ updater.create = options[:create]
171
+ updater.write = options[:write]
172
+ updater.labels = options[:labels] if options[:labels]
173
+ updater
174
+ end
175
+
176
+ ##
177
+ # Sets the geographic location where the job should run. Required
178
+ # except for US and EU.
179
+ #
180
+ # @param [String] value A geographic location, such as "US", "EU" or
181
+ # "asia-northeast1". Required except for US and EU.
182
+ #
183
+ # @example
184
+ # require "google/cloud/bigquery"
185
+ #
186
+ # bigquery = Google::Cloud::Bigquery.new
187
+ # dataset = bigquery.dataset "my_dataset"
188
+ # table = dataset.table "my_table"
189
+ # destination_table = dataset.table "my_destination_table"
190
+ #
191
+ # copy_job = table.copy_job destination_table do |j|
192
+ # j.location = "EU"
193
+ # end
194
+ #
195
+ # copy_job.wait_until_done!
196
+ # copy_job.done? #=> true
197
+ #
198
+ # @!group Attributes
199
+ def location= value
200
+ @gapi.job_reference.location = value
201
+ return unless value.nil?
202
+
203
+ # Treat assigning value of nil the same as unsetting the value.
204
+ unset = @gapi.job_reference.instance_variables.include? :@location
205
+ @gapi.job_reference.remove_instance_variable :@location if unset
206
+ end
207
+
208
+ ##
209
+ # Sets the create disposition.
210
+ #
211
+ # This specifies whether the job is allowed to create new tables. The
212
+ # default value is `needed`.
213
+ #
214
+ # The following values are supported:
215
+ #
216
+ # * `needed` - Create the table if it does not exist.
217
+ # * `never` - The table must already exist. A 'notFound' error is
218
+ # raised if the table does not exist.
219
+ #
220
+ # @param [String] new_create The new create disposition.
221
+ #
222
+ # @!group Attributes
223
+ def create= new_create
224
+ @gapi.configuration.copy.update! create_disposition: Convert.create_disposition(new_create)
225
+ end
226
+
227
+ ##
228
+ # Sets the write disposition.
229
+ #
230
+ # This specifies how to handle data already present in the table. The
231
+ # default value is `append`.
232
+ #
233
+ # The following values are supported:
234
+ #
235
+ # * `truncate` - BigQuery overwrites the table data.
236
+ # * `append` - BigQuery appends the data to the table.
237
+ # * `empty` - An error will be returned if the table already contains
238
+ # data.
239
+ #
240
+ # @param [String] new_write The new write disposition.
241
+ #
242
+ # @!group Attributes
243
+ def write= new_write
244
+ @gapi.configuration.copy.update! write_disposition: Convert.write_disposition(new_write)
245
+ end
246
+
247
+ ##
248
+ # Sets the encryption configuration of the destination table.
249
+ #
250
+ # @param [Google::Cloud::BigQuery::EncryptionConfiguration] val
251
+ # Custom encryption configuration (e.g., Cloud KMS keys).
252
+ #
253
+ # @example
254
+ # require "google/cloud/bigquery"
255
+ #
256
+ # bigquery = Google::Cloud::Bigquery.new
257
+ # dataset = bigquery.dataset "my_dataset"
258
+ # table = dataset.table "my_table"
259
+ #
260
+ # key_name = "projects/a/locations/b/keyRings/c/cryptoKeys/d"
261
+ # encrypt_config = bigquery.encryption kms_key: key_name
262
+ # job = table.copy_job "my_dataset.new_table" do |job|
263
+ # job.encryption = encrypt_config
264
+ # end
265
+ #
266
+ # @!group Attributes
267
+ def encryption= val
268
+ @gapi.configuration.copy.update! destination_encryption_configuration: val.to_gapi
269
+ end
270
+
271
+ ##
272
+ # Sets the labels to use for the job.
273
+ #
274
+ # @param [Hash] value A hash of user-provided labels associated with
275
+ # the job. You can use these to organize and group your jobs. Label
276
+ # keys and values can be no longer than 63 characters, can only
277
+ # contain lowercase letters, numeric characters, underscores and
278
+ # dashes. International characters are allowed. Label values are
279
+ # optional. Label keys must start with a letter and each label in
280
+ # the list must have a different key.
281
+ #
282
+ # @!group Attributes
283
+ def labels= value
284
+ @gapi.configuration.update! labels: value
285
+ end
286
+
287
+ def cancel
288
+ raise "not implemented in #{self.class}"
289
+ end
290
+
291
+ def rerun!
292
+ raise "not implemented in #{self.class}"
293
+ end
294
+
295
+ def reload!
296
+ raise "not implemented in #{self.class}"
297
+ end
298
+ alias refresh! reload!
299
+
300
+ def wait_until_done!
301
+ raise "not implemented in #{self.class}"
302
+ end
303
+
304
+ ##
305
+ # @private Returns the Google API client library version of this job.
306
+ #
307
+ # @return [<Google::Apis::BigqueryV2::Job>] (See
308
+ # {Google::Apis::BigqueryV2::Job})
309
+ def to_gapi
310
+ @gapi
311
+ end
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end