google-cloud-bigquery 1.21.2

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