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,657 @@
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
+
16
+ require "google/cloud/errors"
17
+ require "google/cloud/bigquery/service"
18
+ require "google/cloud/bigquery/job/list"
19
+ require "google/cloud/bigquery/convert"
20
+ require "json"
21
+
22
+ module Google
23
+ module Cloud
24
+ module Bigquery
25
+ ##
26
+ # # Job
27
+ #
28
+ # Represents a generic Job that may be performed on a {Table}.
29
+ #
30
+ # The subclasses of Job represent the specific BigQuery job types:
31
+ # {CopyJob}, {ExtractJob}, {LoadJob}, and {QueryJob}.
32
+ #
33
+ # A job instance is created when you call {Project#query_job},
34
+ # {Dataset#query_job}, {Table#copy_job}, {Table#extract_job},
35
+ # {Table#load_job}.
36
+ #
37
+ # @see https://cloud.google.com/bigquery/docs/managing-jobs Running and
38
+ # Managing Jobs
39
+ # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
40
+ # reference
41
+ #
42
+ # @example
43
+ # require "google/cloud/bigquery"
44
+ #
45
+ # bigquery = Google::Cloud::Bigquery.new
46
+ #
47
+ # job = bigquery.query_job "SELECT COUNT(word) as count FROM " \
48
+ # "`bigquery-public-data.samples.shakespeare`"
49
+ #
50
+ # job.wait_until_done!
51
+ #
52
+ # if job.failed?
53
+ # puts job.error
54
+ # else
55
+ # puts job.data.first
56
+ # end
57
+ #
58
+ class Job
59
+ ##
60
+ # @private The Service object.
61
+ attr_accessor :service
62
+
63
+ ##
64
+ # @private The Google API Client object.
65
+ attr_accessor :gapi
66
+
67
+ ##
68
+ # @private Create an empty Job object.
69
+ def initialize
70
+ @service = nil
71
+ @gapi = {}
72
+ end
73
+
74
+ ##
75
+ # The ID of the job.
76
+ #
77
+ # @return [String] The ID must contain only letters (a-z, A-Z), numbers
78
+ # (0-9), underscores (_), or dashes (-). The maximum length is 1,024
79
+ # characters.
80
+ #
81
+ def job_id
82
+ @gapi.job_reference.job_id
83
+ end
84
+
85
+ ##
86
+ # The ID of the project containing the job.
87
+ #
88
+ # @return [String] The project ID.
89
+ #
90
+ def project_id
91
+ @gapi.job_reference.project_id
92
+ end
93
+
94
+ ##
95
+ # The geographic location where the job runs.
96
+ #
97
+ # @return [String] A geographic location, such as "US", "EU" or
98
+ # "asia-northeast1".
99
+ #
100
+ # @!group Attributes
101
+ def location
102
+ @gapi.job_reference.location
103
+ end
104
+
105
+ ##
106
+ # The email address of the user who ran the job.
107
+ #
108
+ # @return [String] The email address.
109
+ #
110
+ def user_email
111
+ @gapi.user_email
112
+ end
113
+
114
+ ##
115
+ # The current state of the job. A `DONE` state does not mean that the
116
+ # job completed successfully. Use {#failed?} to discover if an error
117
+ # occurred or if the job was successful.
118
+ #
119
+ # @return [String] The state code. The possible values are `PENDING`,
120
+ # `RUNNING`, and `DONE`.
121
+ #
122
+ def state
123
+ return nil if @gapi.status.nil?
124
+ @gapi.status.state
125
+ end
126
+
127
+ ##
128
+ # Checks if the job's state is `RUNNING`.
129
+ #
130
+ # @return [Boolean] `true` when `RUNNING`, `false` otherwise.
131
+ #
132
+ def running?
133
+ return false if state.nil?
134
+ "running".casecmp(state).zero?
135
+ end
136
+
137
+ ##
138
+ # Checks if the job's state is `PENDING`.
139
+ #
140
+ # @return [Boolean] `true` when `PENDING`, `false` otherwise.
141
+ #
142
+ def pending?
143
+ return false if state.nil?
144
+ "pending".casecmp(state).zero?
145
+ end
146
+
147
+ ##
148
+ # Checks if the job's state is `DONE`. When `true`, the job has stopped
149
+ # running. However, a `DONE` state does not mean that the job completed
150
+ # successfully. Use {#failed?} to detect if an error occurred or if the
151
+ # job was successful.
152
+ #
153
+ # @return [Boolean] `true` when `DONE`, `false` otherwise.
154
+ #
155
+ def done?
156
+ return false if state.nil?
157
+ "done".casecmp(state).zero?
158
+ end
159
+
160
+ ##
161
+ # Checks if an error is present. Use {#error} to access the error
162
+ # object.
163
+ #
164
+ # @return [Boolean] `true` when there is an error, `false` otherwise.
165
+ #
166
+ def failed?
167
+ !error.nil?
168
+ end
169
+
170
+ ##
171
+ # The time when the job was created.
172
+ #
173
+ # @return [Time, nil] The creation time from the job statistics.
174
+ #
175
+ def created_at
176
+ Convert.millis_to_time @gapi.statistics.creation_time
177
+ end
178
+
179
+ ##
180
+ # The time when the job was started.
181
+ # This field is present after the job's state changes from `PENDING`
182
+ # to either `RUNNING` or `DONE`.
183
+ #
184
+ # @return [Time, nil] The start time from the job statistics.
185
+ #
186
+ def started_at
187
+ Convert.millis_to_time @gapi.statistics.start_time
188
+ end
189
+
190
+ ##
191
+ # The time when the job ended.
192
+ # This field is present when the job's state is `DONE`.
193
+ #
194
+ # @return [Time, nil] The end time from the job statistics.
195
+ #
196
+ def ended_at
197
+ Convert.millis_to_time @gapi.statistics.end_time
198
+ end
199
+
200
+ ##
201
+ # The number of child jobs executed.
202
+ #
203
+ # @return [Integer] The number of child jobs executed.
204
+ #
205
+ def num_child_jobs
206
+ @gapi.statistics.num_child_jobs || 0
207
+ end
208
+
209
+ ##
210
+ # If this is a child job, the id of the parent.
211
+ #
212
+ # @return [String, nil] The ID of the parent job, or `nil` if not a child job.
213
+ #
214
+ def parent_job_id
215
+ @gapi.statistics.parent_job_id
216
+ end
217
+
218
+ ##
219
+ # The statistics including stack frames for a child job of a script.
220
+ #
221
+ # @return [Google::Cloud::Bigquery::Job::ScriptStatistics, nil] The script statistics, or `nil` if the job is
222
+ # not a child job.
223
+ #
224
+ # @example
225
+ # require "google/cloud/bigquery"
226
+ #
227
+ # bigquery = Google::Cloud::Bigquery.new
228
+ #
229
+ # multi_statement_sql = <<~SQL
230
+ # -- Declare a variable to hold names as an array.
231
+ # DECLARE top_names ARRAY<STRING>;
232
+ # -- Build an array of the top 100 names from the year 2017.
233
+ # SET top_names = (
234
+ # SELECT ARRAY_AGG(name ORDER BY number DESC LIMIT 100)
235
+ # FROM `bigquery-public-data.usa_names.usa_1910_current`
236
+ # WHERE year = 2017
237
+ # );
238
+ # -- Which names appear as words in Shakespeare's plays?
239
+ # SELECT
240
+ # name AS shakespeare_name
241
+ # FROM UNNEST(top_names) AS name
242
+ # WHERE name IN (
243
+ # SELECT word
244
+ # FROM `bigquery-public-data.samples.shakespeare`
245
+ # );
246
+ # SQL
247
+ #
248
+ # job = bigquery.query_job multi_statement_sql
249
+ #
250
+ # job.wait_until_done!
251
+ #
252
+ # child_jobs = bigquery.jobs parent_job: job
253
+ #
254
+ # child_jobs.each do |child_job|
255
+ # script_statistics = child_job.script_statistics
256
+ # puts script_statistics.evaluation_kind
257
+ # script_statistics.stack_frames.each do |stack_frame|
258
+ # puts stack_frame.text
259
+ # end
260
+ # end
261
+ #
262
+ def script_statistics
263
+ ScriptStatistics.from_gapi @gapi.statistics.script_statistics if @gapi.statistics.script_statistics
264
+ end
265
+
266
+ ##
267
+ # The configuration for the job. Returns a hash.
268
+ #
269
+ # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
270
+ # reference
271
+ def configuration
272
+ JSON.parse @gapi.configuration.to_json
273
+ end
274
+ alias config configuration
275
+
276
+ ##
277
+ # The statistics for the job. Returns a hash.
278
+ #
279
+ # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
280
+ # reference
281
+ #
282
+ # @return [Hash] The job statistics.
283
+ #
284
+ def statistics
285
+ JSON.parse @gapi.statistics.to_json
286
+ end
287
+ alias stats statistics
288
+
289
+ ##
290
+ # The job's status. Returns a hash. The values contained in the hash are
291
+ # also exposed by {#state}, {#error}, and {#errors}.
292
+ #
293
+ # @return [Hash] The job status.
294
+ #
295
+ def status
296
+ JSON.parse @gapi.status.to_json
297
+ end
298
+
299
+ ##
300
+ # The last error for the job, if any errors have occurred. Returns a
301
+ # hash.
302
+ #
303
+ # @see https://cloud.google.com/bigquery/docs/reference/v2/jobs Jobs API
304
+ # reference
305
+ #
306
+ # @return [Hash, nil] Returns a hash containing `reason` and `message`
307
+ # keys:
308
+ #
309
+ # {
310
+ # "reason"=>"notFound",
311
+ # "message"=>"Not found: Table bigquery-public-data:samples.BAD_ID"
312
+ # }
313
+ #
314
+ def error
315
+ status["errorResult"]
316
+ end
317
+
318
+ ##
319
+ # The errors for the job, if any errors have occurred. Returns an array
320
+ # of hash objects. See {#error}.
321
+ #
322
+ # @return [Array<Hash>, nil] Returns an array of hashes containing
323
+ # `reason` and `message` keys:
324
+ #
325
+ # {
326
+ # "reason"=>"notFound",
327
+ # "message"=>"Not found: Table bigquery-public-data:samples.BAD_ID"
328
+ # }
329
+ #
330
+ def errors
331
+ Array status["errors"]
332
+ end
333
+
334
+ ##
335
+ # A hash of user-provided labels associated with this job. Labels can be
336
+ # provided when the job is created, and used to organize and group jobs.
337
+ #
338
+ # The returned hash is frozen and changes are not allowed. Use
339
+ # {CopyJob::Updater#labels=} or {ExtractJob::Updater#labels=} or
340
+ # {LoadJob::Updater#labels=} or {QueryJob::Updater#labels=} to replace
341
+ # the entire hash.
342
+ #
343
+ # @return [Hash] The job labels.
344
+ #
345
+ # @!group Attributes
346
+ #
347
+ def labels
348
+ m = @gapi.configuration.labels
349
+ m = m.to_h if m.respond_to? :to_h
350
+ m.dup.freeze
351
+ end
352
+
353
+ ##
354
+ # Cancels the job.
355
+ #
356
+ # @example
357
+ # require "google/cloud/bigquery"
358
+ #
359
+ # bigquery = Google::Cloud::Bigquery.new
360
+ #
361
+ # query = "SELECT COUNT(word) as count FROM " \
362
+ # "`bigquery-public-data.samples.shakespeare`"
363
+ #
364
+ # job = bigquery.query_job query
365
+ #
366
+ # job.cancel
367
+ #
368
+ def cancel
369
+ ensure_service!
370
+ resp = service.cancel_job job_id, location: location
371
+ @gapi = resp.job
372
+ true
373
+ end
374
+
375
+ ##
376
+ # Created a new job with the current configuration.
377
+ #
378
+ # @example
379
+ # require "google/cloud/bigquery"
380
+ #
381
+ # bigquery = Google::Cloud::Bigquery.new
382
+ #
383
+ # query = "SELECT COUNT(word) as count FROM " \
384
+ # "`bigquery-public-data.samples.shakespeare`"
385
+ #
386
+ # job = bigquery.query_job query
387
+ #
388
+ # job.wait_until_done!
389
+ # job.rerun!
390
+ #
391
+ def rerun!
392
+ ensure_service!
393
+ gapi = service.insert_job @gapi.configuration, location: location
394
+ Job.from_gapi gapi, service
395
+ end
396
+
397
+ ##
398
+ # Reloads the job with current data from the BigQuery service.
399
+ #
400
+ # @example
401
+ # require "google/cloud/bigquery"
402
+ #
403
+ # bigquery = Google::Cloud::Bigquery.new
404
+ #
405
+ # query = "SELECT COUNT(word) as count FROM " \
406
+ # "`bigquery-public-data.samples.shakespeare`"
407
+ #
408
+ # job = bigquery.query_job query
409
+ #
410
+ # job.done?
411
+ # job.reload!
412
+ # job.done? #=> true
413
+ #
414
+ def reload!
415
+ ensure_service!
416
+ gapi = service.get_job job_id, location: location
417
+ @gapi = gapi
418
+ end
419
+ alias refresh! reload!
420
+
421
+ ##
422
+ # Refreshes the job until the job is `DONE`. The delay between refreshes
423
+ # starts at 5 seconds and increases exponentially to a maximum of 60
424
+ # seconds.
425
+ #
426
+ # @example
427
+ # require "google/cloud/bigquery"
428
+ #
429
+ # bigquery = Google::Cloud::Bigquery.new
430
+ # dataset = bigquery.dataset "my_dataset"
431
+ # table = dataset.table "my_table"
432
+ #
433
+ # extract_job = table.extract_job "gs://my-bucket/file-name.json",
434
+ # format: "json"
435
+ # extract_job.wait_until_done!
436
+ # extract_job.done? #=> true
437
+ #
438
+ def wait_until_done!
439
+ backoff = lambda do |retries|
440
+ delay = [retries**2 + 5, 60].min # Maximum delay is 60
441
+ sleep delay
442
+ end
443
+ retries = 0
444
+ until done?
445
+ backoff.call retries
446
+ retries += 1
447
+ reload!
448
+ end
449
+ end
450
+
451
+ ##
452
+ # @private New Job from a Google API Client object.
453
+ def self.from_gapi gapi, conn
454
+ klass = klass_for gapi
455
+ klass.new.tap do |f|
456
+ f.gapi = gapi
457
+ f.service = conn
458
+ end
459
+ end
460
+
461
+ ##
462
+ # @private New Google::Apis::Error with job failure details
463
+ def gapi_error
464
+ return nil unless failed?
465
+
466
+ error_status_code = status_code_for_reason error["reason"]
467
+ error_body = error
468
+ error_body["errors"] = errors
469
+
470
+ Google::Apis::Error.new error["message"],
471
+ status_code: error_status_code,
472
+ body: error_body
473
+ end
474
+
475
+ ##
476
+ # @private
477
+ # Get the subclass for a job type
478
+ def self.klass_for gapi
479
+ if gapi.configuration.copy
480
+ CopyJob
481
+ elsif gapi.configuration.extract
482
+ ExtractJob
483
+ elsif gapi.configuration.load
484
+ LoadJob
485
+ elsif gapi.configuration.query
486
+ QueryJob
487
+ else
488
+ Job
489
+ end
490
+ end
491
+
492
+ ##
493
+ # Represents statistics for a child job of a script.
494
+ #
495
+ # @attr_reader [String] evaluation_kind Indicates the type of child job. Possible values include `STATEMENT` and
496
+ # `EXPRESSION`.
497
+ # @attr_reader [Array<Google::Cloud::Bigquery::Job::ScriptStackFrame>] stack_frames Stack trace where the
498
+ # current evaluation happened. Shows line/column/procedure name of each frame on the stack at the point where
499
+ # the current evaluation happened. The leaf frame is first, the primary script is last.
500
+ #
501
+ # @example
502
+ # require "google/cloud/bigquery"
503
+ #
504
+ # bigquery = Google::Cloud::Bigquery.new
505
+ #
506
+ # multi_statement_sql = <<~SQL
507
+ # -- Declare a variable to hold names as an array.
508
+ # DECLARE top_names ARRAY<STRING>;
509
+ # -- Build an array of the top 100 names from the year 2017.
510
+ # SET top_names = (
511
+ # SELECT ARRAY_AGG(name ORDER BY number DESC LIMIT 100)
512
+ # FROM `bigquery-public-data.usa_names.usa_1910_current`
513
+ # WHERE year = 2017
514
+ # );
515
+ # -- Which names appear as words in Shakespeare's plays?
516
+ # SELECT
517
+ # name AS shakespeare_name
518
+ # FROM UNNEST(top_names) AS name
519
+ # WHERE name IN (
520
+ # SELECT word
521
+ # FROM `bigquery-public-data.samples.shakespeare`
522
+ # );
523
+ # SQL
524
+ #
525
+ # job = bigquery.query_job multi_statement_sql
526
+ #
527
+ # job.wait_until_done!
528
+ #
529
+ # child_jobs = bigquery.jobs parent_job: job
530
+ #
531
+ # child_jobs.each do |child_job|
532
+ # script_statistics = child_job.script_statistics
533
+ # puts script_statistics.evaluation_kind
534
+ # script_statistics.stack_frames.each do |stack_frame|
535
+ # puts stack_frame.text
536
+ # end
537
+ # end
538
+ #
539
+ class ScriptStatistics
540
+ attr_reader :evaluation_kind, :stack_frames
541
+
542
+ ##
543
+ # @private Creates a new ScriptStatistics instance.
544
+ def initialize evaluation_kind, stack_frames
545
+ @evaluation_kind = evaluation_kind
546
+ @stack_frames = stack_frames
547
+ end
548
+
549
+ ##
550
+ # @private New ScriptStatistics from a statistics.script_statistics object.
551
+ def self.from_gapi gapi
552
+ frames = Array(gapi.stack_frames).map { |g| ScriptStackFrame.from_gapi g }
553
+ new gapi.evaluation_kind, frames
554
+ end
555
+ end
556
+
557
+ ##
558
+ # Represents a stack frame showing the line/column/procedure name where the current evaluation happened.
559
+ #
560
+ # @attr_reader [Integer] start_line One-based start line.
561
+ # @attr_reader [Integer] start_column One-based start column.
562
+ # @attr_reader [Integer] end_line One-based end line.
563
+ # @attr_reader [Integer] end_column One-based end column.
564
+ # @attr_reader [String] text Text of the current statement/expression.
565
+ #
566
+ # @example
567
+ # require "google/cloud/bigquery"
568
+ #
569
+ # bigquery = Google::Cloud::Bigquery.new
570
+ #
571
+ # multi_statement_sql = <<~SQL
572
+ # -- Declare a variable to hold names as an array.
573
+ # DECLARE top_names ARRAY<STRING>;
574
+ # -- Build an array of the top 100 names from the year 2017.
575
+ # SET top_names = (
576
+ # SELECT ARRAY_AGG(name ORDER BY number DESC LIMIT 100)
577
+ # FROM `bigquery-public-data.usa_names.usa_1910_current`
578
+ # WHERE year = 2017
579
+ # );
580
+ # -- Which names appear as words in Shakespeare's plays?
581
+ # SELECT
582
+ # name AS shakespeare_name
583
+ # FROM UNNEST(top_names) AS name
584
+ # WHERE name IN (
585
+ # SELECT word
586
+ # FROM `bigquery-public-data.samples.shakespeare`
587
+ # );
588
+ # SQL
589
+ #
590
+ # job = bigquery.query_job multi_statement_sql
591
+ #
592
+ # job.wait_until_done!
593
+ #
594
+ # child_jobs = bigquery.jobs parent_job: job
595
+ #
596
+ # child_jobs.each do |child_job|
597
+ # script_statistics = child_job.script_statistics
598
+ # puts script_statistics.evaluation_kind
599
+ # script_statistics.stack_frames.each do |stack_frame|
600
+ # puts stack_frame.text
601
+ # end
602
+ # end
603
+ #
604
+ class ScriptStackFrame
605
+ attr_reader :start_line, :start_column, :end_line, :end_column, :text
606
+
607
+ ##
608
+ # @private Creates a new ScriptStackFrame instance.
609
+ def initialize start_line, start_column, end_line, end_column, text
610
+ @start_line = start_line
611
+ @start_column = start_column
612
+ @end_line = end_line
613
+ @end_column = end_column
614
+ @text = text
615
+ end
616
+
617
+ ##
618
+ # @private New ScriptStackFrame from a statistics.script_statistics[].stack_frames element.
619
+ def self.from_gapi gapi
620
+ new gapi.start_line, gapi.start_column, gapi.end_line, gapi.end_column, gapi.text
621
+ end
622
+ end
623
+
624
+ protected
625
+
626
+ ##
627
+ # Raise an error unless an active connection is available.
628
+ def ensure_service!
629
+ raise "Must have active connection" unless service
630
+ end
631
+
632
+ def retrieve_table project_id, dataset_id, table_id
633
+ ensure_service!
634
+ gapi = service.get_project_table project_id, dataset_id, table_id
635
+ Table.from_gapi gapi, service
636
+ rescue Google::Cloud::NotFoundError
637
+ nil
638
+ end
639
+
640
+ def status_code_for_reason reason
641
+ codes = { "accessDenied" => 403, "backendError" => 500, "billingNotEnabled" => 403,
642
+ "billingTierLimitExceeded" => 400, "blocked" => 403, "duplicate" => 409, "internalError" => 500,
643
+ "invalid" => 400, "invalidQuery" => 400, "notFound" => 404, "notImplemented" => 501,
644
+ "quotaExceeded" => 403, "rateLimitExceeded" => 403, "resourceInUse" => 400,
645
+ "resourcesExceeded" => 400, "responseTooLarge" => 403, "tableUnavailable" => 400 }
646
+ codes[reason] || 0
647
+ end
648
+ end
649
+ end
650
+ end
651
+ end
652
+
653
+ # We need Job to be defined before loading these.
654
+ require "google/cloud/bigquery/copy_job"
655
+ require "google/cloud/bigquery/extract_job"
656
+ require "google/cloud/bigquery/load_job"
657
+ require "google/cloud/bigquery/query_job"