google-cloud-bigquery 1.14.0 → 1.42.0

Sign up to get free protection for your applications and to get access to all the features.
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