google-cloud-bigquery 1.14.0 → 1.42.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHENTICATION.md +17 -54
  3. data/CHANGELOG.md +377 -0
  4. data/CONTRIBUTING.md +328 -116
  5. data/LOGGING.md +1 -1
  6. data/OVERVIEW.md +21 -20
  7. data/TROUBLESHOOTING.md +2 -8
  8. data/lib/google/cloud/bigquery/argument.rb +197 -0
  9. data/lib/google/cloud/bigquery/convert.rb +155 -173
  10. data/lib/google/cloud/bigquery/copy_job.rb +74 -26
  11. data/lib/google/cloud/bigquery/credentials.rb +5 -12
  12. data/lib/google/cloud/bigquery/data.rb +109 -18
  13. data/lib/google/cloud/bigquery/dataset/access.rb +474 -52
  14. data/lib/google/cloud/bigquery/dataset/list.rb +7 -13
  15. data/lib/google/cloud/bigquery/dataset/tag.rb +67 -0
  16. data/lib/google/cloud/bigquery/dataset.rb +1044 -287
  17. data/lib/google/cloud/bigquery/external/avro_source.rb +107 -0
  18. data/lib/google/cloud/bigquery/external/bigtable_source/column.rb +404 -0
  19. data/lib/google/cloud/bigquery/external/bigtable_source/column_family.rb +945 -0
  20. data/lib/google/cloud/bigquery/external/bigtable_source.rb +230 -0
  21. data/lib/google/cloud/bigquery/external/csv_source.rb +481 -0
  22. data/lib/google/cloud/bigquery/external/data_source.rb +771 -0
  23. data/lib/google/cloud/bigquery/external/json_source.rb +170 -0
  24. data/lib/google/cloud/bigquery/external/parquet_source.rb +148 -0
  25. data/lib/google/cloud/bigquery/external/sheets_source.rb +166 -0
  26. data/lib/google/cloud/bigquery/external.rb +50 -2256
  27. data/lib/google/cloud/bigquery/extract_job.rb +226 -61
  28. data/lib/google/cloud/bigquery/insert_response.rb +1 -3
  29. data/lib/google/cloud/bigquery/job/list.rb +10 -14
  30. data/lib/google/cloud/bigquery/job.rb +289 -14
  31. data/lib/google/cloud/bigquery/load_job.rb +810 -136
  32. data/lib/google/cloud/bigquery/model/list.rb +5 -9
  33. data/lib/google/cloud/bigquery/model.rb +247 -16
  34. data/lib/google/cloud/bigquery/policy.rb +432 -0
  35. data/lib/google/cloud/bigquery/project/list.rb +6 -11
  36. data/lib/google/cloud/bigquery/project.rb +509 -250
  37. data/lib/google/cloud/bigquery/query_job.rb +594 -128
  38. data/lib/google/cloud/bigquery/routine/list.rb +165 -0
  39. data/lib/google/cloud/bigquery/routine.rb +1227 -0
  40. data/lib/google/cloud/bigquery/schema/field.rb +413 -63
  41. data/lib/google/cloud/bigquery/schema.rb +221 -48
  42. data/lib/google/cloud/bigquery/service.rb +204 -112
  43. data/lib/google/cloud/bigquery/standard_sql.rb +269 -53
  44. data/lib/google/cloud/bigquery/table/async_inserter.rb +86 -43
  45. data/lib/google/cloud/bigquery/table/list.rb +6 -11
  46. data/lib/google/cloud/bigquery/table.rb +1470 -377
  47. data/lib/google/cloud/bigquery/time.rb +6 -0
  48. data/lib/google/cloud/bigquery/version.rb +1 -1
  49. data/lib/google/cloud/bigquery.rb +4 -6
  50. data/lib/google-cloud-bigquery.rb +14 -13
  51. metadata +66 -38
@@ -43,13 +43,13 @@ module Google
43
43
 
44
44
  ##
45
45
  # Creates a new Service instance.
46
- def initialize project, credentials,
47
- retries: nil, timeout: nil, host: nil
46
+ def initialize project, credentials, retries: nil, timeout: nil, host: nil, quota_project: nil
48
47
  @project = project
49
48
  @credentials = credentials
50
49
  @retries = retries
51
50
  @timeout = timeout
52
51
  @host = host
52
+ @quota_project = quota_project
53
53
  end
54
54
 
55
55
  def service
@@ -57,8 +57,7 @@ module Google
57
57
  @service ||= begin
58
58
  service = API::BigqueryService.new
59
59
  service.client_options.application_name = "gcloud-ruby"
60
- service.client_options.application_version = \
61
- Google::Cloud::Bigquery::VERSION
60
+ service.client_options.application_version = Google::Cloud::Bigquery::VERSION
62
61
  service.client_options.open_timeout_sec = timeout
63
62
  service.client_options.read_timeout_sec = timeout
64
63
  service.client_options.send_timeout_sec = timeout
@@ -66,6 +65,9 @@ module Google
66
65
  service.request_options.header ||= {}
67
66
  service.request_options.header["x-goog-api-client"] = \
68
67
  "gl-ruby/#{RUBY_VERSION} gccl/#{Google::Cloud::Bigquery::VERSION}"
68
+ service.request_options.query ||= {}
69
+ service.request_options.query["prettyPrint"] = false
70
+ service.request_options.quota_project = @quota_project if @quota_project
69
71
  service.authorization = @credentials.client
70
72
  service.root_url = host if host
71
73
  service
@@ -80,12 +82,10 @@ module Google
80
82
  ##
81
83
  # Lists all datasets in the specified project to which you have
82
84
  # been granted the READER dataset role.
83
- def list_datasets options = {}
85
+ def list_datasets all: nil, filter: nil, max: nil, token: nil
84
86
  # The list operation is considered idempotent
85
87
  execute backoff: true do
86
- service.list_datasets \
87
- @project, all: options[:all], filter: options[:filter],
88
- max_results: options[:max], page_token: options[:token]
88
+ service.list_datasets @project, all: all, filter: filter, max_results: max, page_token: token
89
89
  end
90
90
  end
91
91
 
@@ -116,8 +116,7 @@ module Google
116
116
  patch_with_backoff = true
117
117
  end
118
118
  execute backoff: patch_with_backoff do
119
- service.patch_dataset @project, dataset_id, patched_dataset_gapi,
120
- options: options
119
+ service.patch_dataset @project, dataset_id, patched_dataset_gapi, options: options
121
120
  end
122
121
  end
123
122
 
@@ -136,19 +135,20 @@ module Google
136
135
  ##
137
136
  # Lists all tables in the specified dataset.
138
137
  # Requires the READER dataset role.
139
- def list_tables dataset_id, options = {}
138
+ def list_tables dataset_id, max: nil, token: nil
140
139
  # The list operation is considered idempotent
141
140
  execute backoff: true do
142
- service.list_tables @project, dataset_id,
143
- max_results: options[:max],
144
- page_token: options[:token]
141
+ service.list_tables @project, dataset_id, max_results: max, page_token: token
145
142
  end
146
143
  end
147
144
 
148
- def get_project_table project_id, dataset_id, table_id
145
+ ##
146
+ # Gets the specified table resource by full table reference.
147
+ def get_project_table project_id, dataset_id, table_id, metadata_view: nil
148
+ metadata_view = table_metadata_view_type_for metadata_view
149
149
  # The get operation is considered idempotent
150
150
  execute backoff: true do
151
- service.get_table project_id, dataset_id, table_id
151
+ service.get_table project_id, dataset_id, table_id, view: metadata_view
152
152
  end
153
153
  end
154
154
 
@@ -157,11 +157,8 @@ module Google
157
157
  # This method does not return the data in the table,
158
158
  # it only returns the table resource,
159
159
  # which describes the structure of this table.
160
- def get_table dataset_id, table_id
161
- # The get operation is considered idempotent
162
- execute backoff: true do
163
- get_project_table @project, dataset_id, table_id
164
- end
160
+ def get_table dataset_id, table_id, metadata_view: nil
161
+ get_project_table @project, dataset_id, table_id, metadata_view: metadata_view
165
162
  end
166
163
 
167
164
  ##
@@ -182,8 +179,35 @@ module Google
182
179
  patch_with_backoff = true
183
180
  end
184
181
  execute backoff: patch_with_backoff do
185
- service.patch_table @project, dataset_id, table_id,
186
- patched_table_gapi, options: options
182
+ service.patch_table @project, dataset_id, table_id, patched_table_gapi, options: options
183
+ end
184
+ end
185
+
186
+ ##
187
+ # Returns Google::Apis::BigqueryV2::Policy
188
+ def get_table_policy dataset_id, table_id
189
+ policy_options = API::GetPolicyOptions.new requested_policy_version: 1
190
+ execute do
191
+ service.get_table_iam_policy table_path(dataset_id, table_id),
192
+ API::GetIamPolicyRequest.new(options: policy_options)
193
+ end
194
+ end
195
+
196
+ ##
197
+ # @param [Google::Apis::BigqueryV2::Policy] new_policy
198
+ def set_table_policy dataset_id, table_id, new_policy
199
+ execute do
200
+ service.set_table_iam_policy table_path(dataset_id, table_id),
201
+ API::SetIamPolicyRequest.new(policy: new_policy)
202
+ end
203
+ end
204
+
205
+ ##
206
+ # Returns Google::Apis::BigqueryV2::TestIamPermissionsResponse
207
+ def test_table_permissions dataset_id, table_id, permissions
208
+ execute do
209
+ service.test_table_iam_permissions table_path(dataset_id, table_id),
210
+ API::TestIamPermissionsRequest.new(permissions: permissions)
187
211
  end
188
212
  end
189
213
 
@@ -196,40 +220,45 @@ module Google
196
220
 
197
221
  ##
198
222
  # Retrieves data from the table.
199
- def list_tabledata dataset_id, table_id, options = {}
223
+ def list_tabledata dataset_id, table_id, max: nil, token: nil, start: nil
200
224
  # The list operation is considered idempotent
201
225
  execute backoff: true do
202
226
  json_txt = service.list_table_data \
203
227
  @project, dataset_id, table_id,
204
- max_results: options.delete(:max),
205
- page_token: options.delete(:token),
206
- start_index: options.delete(:start),
228
+ max_results: max,
229
+ page_token: token,
230
+ start_index: start,
207
231
  options: { skip_deserialization: true }
208
232
  JSON.parse json_txt, symbolize_names: true
209
233
  end
210
234
  end
211
235
 
212
- def insert_tabledata dataset_id, table_id, rows, options = {}
236
+ def insert_tabledata dataset_id, table_id, rows, insert_ids: nil, ignore_unknown: nil, skip_invalid: nil
213
237
  json_rows = Array(rows).map { |row| Convert.to_json_row row }
214
- insert_tabledata_json_rows dataset_id, table_id, json_rows, options
238
+ insert_tabledata_json_rows dataset_id, table_id, json_rows, insert_ids: insert_ids,
239
+ ignore_unknown: ignore_unknown,
240
+ skip_invalid: skip_invalid
215
241
  end
216
242
 
217
- def insert_tabledata_json_rows dataset_id, table_id, json_rows,
218
- options = {}
219
-
220
- rows_and_ids = Array(json_rows).zip Array(options[:insert_ids])
243
+ def insert_tabledata_json_rows dataset_id, table_id, json_rows, insert_ids: nil, ignore_unknown: nil,
244
+ skip_invalid: nil
245
+ rows_and_ids = Array(json_rows).zip Array(insert_ids)
221
246
  insert_rows = rows_and_ids.map do |json_row, insert_id|
222
- insert_id ||= SecureRandom.uuid
223
- {
224
- insertId: insert_id,
225
- json: json_row
226
- }
247
+ if insert_id == :skip
248
+ { json: json_row }
249
+ else
250
+ insert_id ||= SecureRandom.uuid
251
+ {
252
+ insertId: insert_id,
253
+ json: json_row
254
+ }
255
+ end
227
256
  end
228
257
 
229
258
  insert_req = {
230
259
  rows: insert_rows,
231
- ignoreUnknownValues: options[:ignore_unknown],
232
- skipInvalidRows: options[:skip_invalid]
260
+ ignoreUnknownValues: ignore_unknown,
261
+ skipInvalidRows: skip_invalid
233
262
  }.to_json
234
263
 
235
264
  # The insertAll with insertId operation is considered idempotent
@@ -248,27 +277,26 @@ module Google
248
277
  options = { skip_deserialization: true }
249
278
  # The list operation is considered idempotent
250
279
  execute backoff: true do
251
- json_txt = service.list_models @project, dataset_id,
252
- max_results: max,
253
- page_token: token,
254
- options: options
280
+ json_txt = service.list_models @project, dataset_id, max_results: max, page_token: token, options: options
255
281
  JSON.parse json_txt, symbolize_names: true
256
282
  end
257
283
  end
258
284
 
259
- # Gets the specified model resource by model ID.
260
- # This method does not return the data in the model,
261
- # it only returns the model resource,
262
- # which describes the structure of this model.
263
- def get_model dataset_id, model_id
285
+ # Gets the specified model resource by full model reference.
286
+ def get_project_model project_id, dataset_id, model_id
264
287
  # The get operation is considered idempotent
265
288
  execute backoff: true do
266
- json_txt = service.get_model @project, dataset_id, model_id,
267
- options: { skip_deserialization: true }
289
+ json_txt = service.get_model project_id, dataset_id, model_id, options: { skip_deserialization: true }
268
290
  JSON.parse json_txt, symbolize_names: true
269
291
  end
270
292
  end
271
293
 
294
+ # Gets the specified model resource by model ID. This method does not return the data in the model, it only
295
+ # returns the model resource, which describes the structure of this model.
296
+ def get_model dataset_id, model_id
297
+ get_project_model @project, dataset_id, model_id
298
+ end
299
+
272
300
  ##
273
301
  # Updates information in an existing model, replacing fields that
274
302
  # are provided in the submitted model resource.
@@ -281,9 +309,7 @@ module Google
281
309
  patch_with_backoff = true
282
310
  end
283
311
  execute backoff: patch_with_backoff do
284
- json_txt = service.patch_model @project, dataset_id, model_id,
285
- patched_model_gapi,
286
- options: options
312
+ json_txt = service.patch_model @project, dataset_id, model_id, patched_model_gapi, options: options
287
313
  JSON.parse json_txt, symbolize_names: true
288
314
  end
289
315
  end
@@ -295,20 +321,69 @@ module Google
295
321
  execute { service.delete_model @project, dataset_id, model_id }
296
322
  end
297
323
 
324
+ ##
325
+ # Creates a new routine in the dataset.
326
+ def insert_routine dataset_id, new_routine_gapi
327
+ execute { service.insert_routine @project, dataset_id, new_routine_gapi }
328
+ end
329
+
330
+ ##
331
+ # Lists all routines in the specified dataset.
332
+ # Requires the READER dataset role.
333
+ # Unless readMask is set in the request, only the following fields are populated:
334
+ # etag, projectId, datasetId, routineId, routineType, creationTime, lastModifiedTime, and language.
335
+ def list_routines dataset_id, max: nil, token: nil, filter: nil
336
+ # The list operation is considered idempotent
337
+ execute backoff: true do
338
+ service.list_routines @project, dataset_id, max_results: max,
339
+ page_token: token,
340
+ filter: filter
341
+ end
342
+ end
343
+
344
+ ##
345
+ # Gets the specified routine resource by routine ID.
346
+ def get_routine dataset_id, routine_id
347
+ # The get operation is considered idempotent
348
+ execute backoff: true do
349
+ service.get_routine @project, dataset_id, routine_id
350
+ end
351
+ end
352
+
353
+ ##
354
+ # Updates information in an existing routine, replacing the entire routine resource.
355
+ def update_routine dataset_id, routine_id, new_routine_gapi
356
+ update_with_backoff = false
357
+ options = {}
358
+ if new_routine_gapi.etag
359
+ options[:header] = { "If-Match" => new_routine_gapi.etag }
360
+ # The update with etag operation is considered idempotent
361
+ update_with_backoff = true
362
+ end
363
+ execute backoff: update_with_backoff do
364
+ service.update_routine @project, dataset_id, routine_id, new_routine_gapi, options: options
365
+ end
366
+ end
367
+
368
+ ##
369
+ # Deletes the routine specified by routine_id from the dataset.
370
+ def delete_routine dataset_id, routine_id
371
+ execute { service.delete_routine @project, dataset_id, routine_id }
372
+ end
373
+
298
374
  ##
299
375
  # Lists all jobs in the specified project to which you have
300
376
  # been granted the READER job role.
301
- def list_jobs options = {}
377
+ def list_jobs all: nil, token: nil, max: nil, filter: nil, min_created_at: nil, max_created_at: nil,
378
+ parent_job_id: nil
302
379
  # The list operation is considered idempotent
303
- min_creation_time = Convert.time_to_millis options[:min_created_at]
304
- max_creation_time = Convert.time_to_millis options[:max_created_at]
380
+ min_creation_time = Convert.time_to_millis min_created_at
381
+ max_creation_time = Convert.time_to_millis max_created_at
305
382
  execute backoff: true do
306
- service.list_jobs \
307
- @project, all_users: options[:all], max_results: options[:max],
308
- page_token: options[:token], projection: "full",
309
- state_filter: options[:filter],
310
- min_creation_time: min_creation_time,
311
- max_creation_time: max_creation_time
383
+ service.list_jobs @project, all_users: all, max_results: max,
384
+ page_token: token, projection: "full", state_filter: filter,
385
+ min_creation_time: min_creation_time, max_creation_time: max_creation_time,
386
+ parent_job_id: parent_job_id
312
387
  end
313
388
  end
314
389
 
@@ -331,10 +406,7 @@ module Google
331
406
  end
332
407
 
333
408
  def insert_job config, location: nil
334
- job_object = API::Job.new(
335
- job_reference: job_ref_from(nil, nil, location: location),
336
- configuration: config
337
- )
409
+ job_object = API::Job.new job_reference: job_ref_from(nil, nil, location: location), configuration: config
338
410
  # Jobs have generated id, so this operation is considered idempotent
339
411
  execute backoff: true do
340
412
  service.insert_job @project, job_object
@@ -347,18 +419,25 @@ module Google
347
419
  end
348
420
  end
349
421
 
422
+ ##
423
+ # Deletes the job specified by jobId and location (required).
424
+ def delete_job job_id, location: nil
425
+ execute do
426
+ service.delete_job @project, job_id, location: location
427
+ end
428
+ end
429
+
350
430
  ##
351
431
  # Returns the query data for the job
352
- def job_query_results job_id, options = {}
432
+ def job_query_results job_id, location: nil, max: nil, token: nil, start: nil, timeout: nil
353
433
  # The get operation is considered idempotent
354
434
  execute backoff: true do
355
- service.get_job_query_results \
356
- @project, job_id,
357
- location: options.delete(:location),
358
- max_results: options.delete(:max),
359
- page_token: options.delete(:token),
360
- start_index: options.delete(:start),
361
- timeout_ms: options.delete(:timeout)
435
+ service.get_job_query_results @project, job_id,
436
+ location: location,
437
+ max_results: max,
438
+ page_token: token,
439
+ start_index: start,
440
+ timeout_ms: timeout
362
441
  end
363
442
  end
364
443
 
@@ -382,10 +461,7 @@ module Google
382
461
 
383
462
  def load_table_file file, load_job_gapi
384
463
  execute backoff: true do
385
- service.insert_job \
386
- @project,
387
- load_job_gapi,
388
- upload_source: file, content_type: mime_type_for(file)
464
+ service.insert_job @project, load_job_gapi, upload_source: file, content_type: mime_type_for(file)
389
465
  end
390
466
  end
391
467
 
@@ -409,34 +485,42 @@ module Google
409
485
  def self.table_ref_from_s str, default_ref: {}
410
486
  str = str.to_s
411
487
  m = /\A(((?<prj>\S*)(:|\.))?(?<dts>\S*)\.)?(?<tbl>\S*)\z/.match str
412
- unless m
413
- raise ArgumentError, "unable to identify table from #{str.inspect}"
414
- end
488
+ raise ArgumentError, "unable to identify table from #{str.inspect}" unless m
415
489
  str_table_ref_hash = {
416
490
  project_id: m["prj"],
417
491
  dataset_id: m["dts"],
418
492
  table_id: m["tbl"]
419
493
  }.delete_if { |_, v| v.nil? }
420
494
  str_table_ref_hash = default_ref.to_h.merge str_table_ref_hash
421
- ref = Google::Apis::BigqueryV2::TableReference.new str_table_ref_hash
495
+ ref = Google::Apis::BigqueryV2::TableReference.new(**str_table_ref_hash)
422
496
  validate_table_ref ref
423
497
  ref
424
498
  end
425
499
 
500
+ ##
501
+ # Converts a hash to a Google::Apis::BigqueryV2::DatasetAccessEntry oject.
502
+ #
503
+ # @param [Hash<String,String>] dataset_hash Hash for a DatasetAccessEntry.
504
+ #
505
+ def self.dataset_access_entry_from_hash dataset_hash
506
+ params = {
507
+ dataset: Google::Apis::BigqueryV2::DatasetReference.new(**dataset_hash),
508
+ target_types: dataset_hash[:target_types]
509
+ }.delete_if { |_, v| v.nil? }
510
+ Google::Apis::BigqueryV2::DatasetAccessEntry.new(**params)
511
+ end
512
+
426
513
  def self.validate_table_ref table_ref
427
- %i[project_id dataset_id table_id].each do |f|
428
- if table_ref.send(f).nil?
429
- raise ArgumentError, "TableReference is missing #{f}"
430
- end
514
+ [:project_id, :dataset_id, :table_id].each do |f|
515
+ raise ArgumentError, "TableReference is missing #{f}" if table_ref.send(f).nil?
431
516
  end
432
517
  end
433
518
 
434
519
  ##
435
520
  # Lists all projects to which you have been granted any project role.
436
- def list_projects options = {}
521
+ def list_projects max: nil, token: nil
437
522
  execute backoff: true do
438
- service.list_projects max_results: options[:max],
439
- page_token: options[:token]
523
+ service.list_projects max_results: max, page_token: token
440
524
  end
441
525
  end
442
526
 
@@ -446,10 +530,7 @@ module Google
446
530
  def job_ref_from job_id, prefix, location: nil
447
531
  prefix ||= "job_"
448
532
  job_id ||= "#{prefix}#{generate_id}"
449
- job_ref = API::JobReference.new(
450
- project_id: @project,
451
- job_id: job_id
452
- )
533
+ job_ref = API::JobReference.new project_id: @project, job_id: job_id
453
534
  # BigQuery does not allow nil location, but missing is ok.
454
535
  job_ref.location = location if location
455
536
  job_ref
@@ -477,6 +558,11 @@ module Google
477
558
 
478
559
  protected
479
560
 
561
+ # Creates a formatted table path.
562
+ def table_path dataset_id, table_id
563
+ "projects/#{@project}/datasets/#{dataset_id}/tables/#{table_id}"
564
+ end
565
+
480
566
  # Generate a random string similar to the BigQuery service job IDs.
481
567
  def generate_id
482
568
  SecureRandom.urlsafe_base64 21
@@ -490,9 +576,9 @@ module Google
490
576
  nil
491
577
  end
492
578
 
493
- def execute backoff: nil
579
+ def execute backoff: nil, &block
494
580
  if backoff
495
- Backoff.new(retries: retries).execute { yield }
581
+ Backoff.new(retries: retries).execute(&block)
496
582
  else
497
583
  yield
498
584
  end
@@ -500,6 +586,14 @@ module Google
500
586
  raise Google::Cloud::Error.from_error e
501
587
  end
502
588
 
589
+ def table_metadata_view_type_for str
590
+ return nil if str.nil?
591
+ { "unspecified" => "TABLE_METADATA_VIEW_UNSPECIFIED",
592
+ "basic" => "BASIC",
593
+ "storage" => "STORAGE_STATS",
594
+ "full" => "FULL" }[str.to_s.downcase]
595
+ end
596
+
503
597
  class Backoff
504
598
  class << self
505
599
  attr_accessor :retries
@@ -507,7 +601,7 @@ module Google
507
601
  attr_accessor :backoff
508
602
  end
509
603
  self.retries = 5
510
- self.reasons = %w[rateLimitExceeded backendError]
604
+ self.reasons = ["rateLimitExceeded", "backendError"]
511
605
  self.backoff = lambda do |retries|
512
606
  # Max delay is 32 seconds
513
607
  # See "Back-off Requirements" here:
@@ -517,31 +611,29 @@ module Google
517
611
  sleep delay
518
612
  end
519
613
 
520
- def initialize options = {}
521
- @retries = (options[:retries] || Backoff.retries).to_i
522
- @reasons = (options[:reasons] || Backoff.reasons).to_a
523
- @backoff = options[:backoff] || Backoff.backoff
614
+ def initialize retries: nil, reasons: nil, backoff: nil
615
+ @retries = (retries || Backoff.retries).to_i
616
+ @reasons = (reasons || Backoff.reasons).to_a
617
+ @backoff = backoff || Backoff.backoff
524
618
  end
525
619
 
526
620
  def execute
527
621
  current_retries = 0
528
622
  loop do
529
- begin
530
- return yield
531
- rescue Google::Apis::Error => e
532
- raise e unless retry? e.body, current_retries
533
-
534
- @backoff.call current_retries
535
- current_retries += 1
536
- end
623
+ return yield
624
+ rescue Google::Apis::Error => e
625
+ raise e unless retry? e.body, current_retries
626
+
627
+ @backoff.call current_retries
628
+ current_retries += 1
537
629
  end
538
630
  end
539
631
 
540
632
  protected
541
633
 
542
- def retry? result, current_retries #:nodoc:
543
- if current_retries < @retries
544
- return true if retry_error_reason? result
634
+ def retry? result, current_retries
635
+ if current_retries < @retries && retry_error_reason?(result)
636
+ return true
545
637
  end
546
638
  false
547
639
  end