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,3340 @@
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/data"
19
+ require "google/cloud/bigquery/table/list"
20
+ require "google/cloud/bigquery/schema"
21
+ require "google/cloud/bigquery/encryption_configuration"
22
+ require "google/cloud/bigquery/external"
23
+ require "google/cloud/bigquery/insert_response"
24
+ require "google/cloud/bigquery/table/async_inserter"
25
+ require "google/cloud/bigquery/convert"
26
+ require "google/apis/bigquery_v2"
27
+
28
+ module Google
29
+ module Cloud
30
+ module Bigquery
31
+ ##
32
+ # # Table
33
+ #
34
+ # A named resource representing a BigQuery table that holds zero or more
35
+ # records. Every table is defined by a schema that may contain nested and
36
+ # repeated fields.
37
+ #
38
+ # The Table class can also represent a
39
+ # [view](https://cloud.google.com/bigquery/docs/views), which is a virtual
40
+ # table defined by a SQL query. BigQuery's views are logical views, not
41
+ # materialized views, which means that the query that defines the view is
42
+ # re-executed every time the view is queried. Queries are billed according
43
+ # to the total amount of data in all table fields referenced directly or
44
+ # indirectly by the top-level query. (See {#view?}, {#query}, {#query=},
45
+ # and {Dataset#create_view}.)
46
+ #
47
+ # @see https://cloud.google.com/bigquery/docs/loading-data#loading_denormalized_nested_and_repeated_data
48
+ # Loading denormalized, nested, and repeated data
49
+ #
50
+ # @example
51
+ # require "google/cloud/bigquery"
52
+ #
53
+ # bigquery = Google::Cloud::Bigquery.new
54
+ # dataset = bigquery.dataset "my_dataset"
55
+ #
56
+ # table = dataset.create_table "my_table" do |schema|
57
+ # schema.string "first_name", mode: :required
58
+ # schema.record "cities_lived", mode: :repeated do |nested_schema|
59
+ # nested_schema.string "place", mode: :required
60
+ # nested_schema.integer "number_of_years", mode: :required
61
+ # end
62
+ # end
63
+ #
64
+ # row = {
65
+ # "first_name" => "Alice",
66
+ # "cities_lived" => [
67
+ # {
68
+ # "place" => "Seattle",
69
+ # "number_of_years" => 5
70
+ # },
71
+ # {
72
+ # "place" => "Stockholm",
73
+ # "number_of_years" => 6
74
+ # }
75
+ # ]
76
+ # }
77
+ # table.insert row
78
+ #
79
+ # @example Creating a BigQuery view:
80
+ # require "google/cloud/bigquery"
81
+ #
82
+ # bigquery = Google::Cloud::Bigquery.new
83
+ # dataset = bigquery.dataset "my_dataset"
84
+ # view = dataset.create_view "my_view",
85
+ # "SELECT name, age FROM `my_project.my_dataset.my_table`"
86
+ # view.view? # true
87
+ #
88
+ class Table
89
+ ##
90
+ # @private The Service object.
91
+ attr_accessor :service
92
+
93
+ ##
94
+ # @private The Google API Client object.
95
+ attr_accessor :gapi
96
+
97
+ ##
98
+ # @private A Google API Client Table Reference object.
99
+ attr_reader :reference
100
+
101
+ ##
102
+ # @private Create an empty Table object.
103
+ def initialize
104
+ @service = nil
105
+ @gapi = nil
106
+ @reference = nil
107
+ end
108
+
109
+ ##
110
+ # A unique ID for this table.
111
+ #
112
+ # @return [String] The ID must contain only letters (a-z, A-Z), numbers
113
+ # (0-9), or underscores (_). The maximum length is 1,024 characters.
114
+ #
115
+ # @!group Attributes
116
+ #
117
+ def table_id
118
+ return reference.table_id if reference?
119
+ @gapi.table_reference.table_id
120
+ end
121
+
122
+ ##
123
+ # The ID of the `Dataset` containing this table.
124
+ #
125
+ # @return [String] The ID must contain only letters (a-z, A-Z), numbers
126
+ # (0-9), or underscores (_). The maximum length is 1,024 characters.
127
+ #
128
+ # @!group Attributes
129
+ #
130
+ def dataset_id
131
+ return reference.dataset_id if reference?
132
+ @gapi.table_reference.dataset_id
133
+ end
134
+
135
+ ##
136
+ # The ID of the `Project` containing this table.
137
+ #
138
+ # @return [String] The project ID.
139
+ #
140
+ # @!group Attributes
141
+ #
142
+ def project_id
143
+ return reference.project_id if reference?
144
+ @gapi.table_reference.project_id
145
+ end
146
+
147
+ ##
148
+ # @private The gapi fragment containing the Project ID, Dataset ID, and
149
+ # Table ID.
150
+ #
151
+ # @return [Google::Apis::BigqueryV2::TableReference]
152
+ #
153
+ def table_ref
154
+ reference? ? reference : @gapi.table_reference
155
+ end
156
+
157
+ ###
158
+ # Checks if the table is range partitioned. See [Creating and using integer range partitioned
159
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
160
+ #
161
+ # @return [Boolean, nil] `true` when the table is range partitioned, or
162
+ # `false` otherwise, if the object is a resource (see {#resource?});
163
+ # `nil` if the object is a reference (see {#reference?}).
164
+ #
165
+ # @!group Attributes
166
+ #
167
+ def range_partitioning?
168
+ return nil if reference?
169
+ !@gapi.range_partitioning.nil?
170
+ end
171
+
172
+ ###
173
+ # The field on which the table is range partitioned, if any. The field must be a top-level `NULLABLE/REQUIRED`
174
+ # field. The only supported type is `INTEGER/INT64`. See [Creating and using integer range partitioned
175
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
176
+ #
177
+ # @return [Integer, nil] The range partition field, or `nil` if not range partitioned or the object is a
178
+ # reference (see {#reference?}).
179
+ #
180
+ # @!group Attributes
181
+ #
182
+ def range_partitioning_field
183
+ return nil if reference?
184
+ ensure_full_data!
185
+ @gapi.range_partitioning.field if range_partitioning?
186
+ end
187
+
188
+ ###
189
+ # The start of range partitioning, inclusive. See [Creating and using integer range partitioned
190
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
191
+ #
192
+ # @return [Integer, nil] The start of range partitioning, inclusive, or `nil` if not range partitioned or the
193
+ # object is a reference (see {#reference?}).
194
+ #
195
+ # @!group Attributes
196
+ #
197
+ def range_partitioning_start
198
+ return nil if reference?
199
+ ensure_full_data!
200
+ @gapi.range_partitioning.range.start if range_partitioning?
201
+ end
202
+
203
+ ###
204
+ # The width of each interval. See [Creating and using integer range partitioned
205
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
206
+ #
207
+ # @return [Integer, nil] The width of each interval, for data in range partitions, or `nil` if not range
208
+ # partitioned or the object is a reference (see {#reference?}).
209
+ #
210
+ # @!group Attributes
211
+ #
212
+ def range_partitioning_interval
213
+ return nil if reference?
214
+ ensure_full_data!
215
+ return nil unless range_partitioning?
216
+ @gapi.range_partitioning.range.interval
217
+ end
218
+
219
+ ###
220
+ # The end of range partitioning, exclusive. See [Creating and using integer range partitioned
221
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
222
+ #
223
+ # @return [Integer, nil] The end of range partitioning, exclusive, or `nil` if not range partitioned or the
224
+ # object is a reference (see {#reference?}).
225
+ #
226
+ # @!group Attributes
227
+ #
228
+ def range_partitioning_end
229
+ return nil if reference?
230
+ ensure_full_data!
231
+ @gapi.range_partitioning.range.end if range_partitioning?
232
+ end
233
+
234
+ ###
235
+ # Checks if the table is time partitioned. See [Partitioned
236
+ # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
237
+ #
238
+ # @return [Boolean, nil] `true` when the table is time partitioned, or
239
+ # `false` otherwise, if the object is a resource (see {#resource?});
240
+ # `nil` if the object is a reference (see {#reference?}).
241
+ #
242
+ # @!group Attributes
243
+ #
244
+ def time_partitioning?
245
+ return nil if reference?
246
+ !@gapi.time_partitioning.nil?
247
+ end
248
+
249
+ ###
250
+ # The period for which the table is time partitioned, if any. See
251
+ # [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
252
+ #
253
+ # @return [String, nil] The time partition type. Currently the only supported
254
+ # value is "DAY", or `nil` if the object is a reference (see
255
+ # {#reference?}).
256
+ #
257
+ # @!group Attributes
258
+ #
259
+ def time_partitioning_type
260
+ return nil if reference?
261
+ ensure_full_data!
262
+ @gapi.time_partitioning.type if time_partitioning?
263
+ end
264
+
265
+ ##
266
+ # Sets the time partitioning type for the table. See [Partitioned
267
+ # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
268
+ #
269
+ # You can only set time partitioning when creating a table as in
270
+ # the example below. BigQuery does not allow you to change time partitioning
271
+ # on an existing table.
272
+ #
273
+ # @param [String] type The time partition type. Currently the only
274
+ # supported value is "DAY".
275
+ #
276
+ # @example
277
+ # require "google/cloud/bigquery"
278
+ #
279
+ # bigquery = Google::Cloud::Bigquery.new
280
+ # dataset = bigquery.dataset "my_dataset"
281
+ # table = dataset.create_table "my_table" do |t|
282
+ # t.schema do |schema|
283
+ # schema.timestamp "dob", mode: :required
284
+ # end
285
+ # t.time_partitioning_type = "DAY"
286
+ # t.time_partitioning_field = "dob"
287
+ # end
288
+ #
289
+ # @!group Attributes
290
+ #
291
+ def time_partitioning_type= type
292
+ reload! unless resource_full?
293
+ @gapi.time_partitioning ||= Google::Apis::BigqueryV2::TimePartitioning.new
294
+ @gapi.time_partitioning.type = type
295
+ patch_gapi! :time_partitioning
296
+ end
297
+
298
+ ###
299
+ # The field on which the table is time partitioned, if any. If not
300
+ # set, the destination table is time partitioned by pseudo column
301
+ # `_PARTITIONTIME`; if set, the table is time partitioned by this field. See
302
+ # [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
303
+ #
304
+ # @return [String, nil] The time partition field, if a field was configured.
305
+ # `nil` if not time partitioned, not set (time partitioned by pseudo column
306
+ # '_PARTITIONTIME') or the object is a reference (see {#reference?}).
307
+ #
308
+ # @!group Attributes
309
+ #
310
+ def time_partitioning_field
311
+ return nil if reference?
312
+ ensure_full_data!
313
+ @gapi.time_partitioning.field if time_partitioning?
314
+ end
315
+
316
+ ##
317
+ # Sets the field on which to time partition the table. If not
318
+ # set, the destination table is time partitioned by pseudo column
319
+ # `_PARTITIONTIME`; if set, the table is time partitioned by this field. See
320
+ # [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
321
+ # The table must also be time partitioned.
322
+ #
323
+ # See {Table#time_partitioning_type=}.
324
+ #
325
+ # You can only set the time partitioning field while creating a table as in
326
+ # the example below. BigQuery does not allow you to change time partitioning
327
+ # on an existing table.
328
+ #
329
+ # @param [String] field The time partition field. The field must be a
330
+ # top-level TIMESTAMP or DATE field. Its mode must be NULLABLE or
331
+ # REQUIRED.
332
+ #
333
+ # @example
334
+ # require "google/cloud/bigquery"
335
+ #
336
+ # bigquery = Google::Cloud::Bigquery.new
337
+ # dataset = bigquery.dataset "my_dataset"
338
+ # table = dataset.create_table "my_table" do |t|
339
+ # t.schema do |schema|
340
+ # schema.timestamp "dob", mode: :required
341
+ # end
342
+ # t.time_partitioning_type = "DAY"
343
+ # t.time_partitioning_field = "dob"
344
+ # end
345
+ #
346
+ # @!group Attributes
347
+ #
348
+ def time_partitioning_field= field
349
+ reload! unless resource_full?
350
+ @gapi.time_partitioning ||= Google::Apis::BigqueryV2::TimePartitioning.new
351
+ @gapi.time_partitioning.field = field
352
+ patch_gapi! :time_partitioning
353
+ end
354
+
355
+ ###
356
+ # The expiration for the time partitions, if any, in seconds. See
357
+ # [Partitioned Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
358
+ #
359
+ # @return [Integer, nil] The expiration time, in seconds, for data in
360
+ # time partitions, or `nil` if not present or the object is a reference
361
+ # (see {#reference?}).
362
+ #
363
+ # @!group Attributes
364
+ #
365
+ def time_partitioning_expiration
366
+ return nil if reference?
367
+ ensure_full_data!
368
+ return nil unless time_partitioning?
369
+ return nil if @gapi.time_partitioning.expiration_ms.nil?
370
+ @gapi.time_partitioning.expiration_ms / 1_000
371
+ end
372
+
373
+ ##
374
+ # Sets the time partition expiration for the table. See [Partitioned
375
+ # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
376
+ # The table must also be time partitioned.
377
+ #
378
+ # See {Table#time_partitioning_type=}.
379
+ #
380
+ # If the table is not a full resource representation (see
381
+ # {#resource_full?}), the full representation will be retrieved before
382
+ # the update to comply with ETag-based optimistic concurrency control.
383
+ #
384
+ # @param [Integer] expiration An expiration time, in seconds,
385
+ # for data in time partitions.
386
+ #
387
+ # @example
388
+ # require "google/cloud/bigquery"
389
+ #
390
+ # bigquery = Google::Cloud::Bigquery.new
391
+ # dataset = bigquery.dataset "my_dataset"
392
+ # table = dataset.create_table "my_table" do |t|
393
+ # t.schema do |schema|
394
+ # schema.timestamp "dob", mode: :required
395
+ # end
396
+ # t.time_partitioning_type = "DAY"
397
+ # t.time_partitioning_field = "dob"
398
+ # t.time_partitioning_expiration = 86_400
399
+ # end
400
+ #
401
+ # @!group Attributes
402
+ #
403
+ def time_partitioning_expiration= expiration
404
+ reload! unless resource_full?
405
+ @gapi.time_partitioning ||= Google::Apis::BigqueryV2::TimePartitioning.new
406
+ @gapi.time_partitioning.expiration_ms = expiration * 1000
407
+ patch_gapi! :time_partitioning
408
+ end
409
+
410
+ ###
411
+ # Whether queries over this table require a partition filter that can be
412
+ # used for partition elimination to be specified. See [Partitioned
413
+ # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
414
+ #
415
+ # @return [Boolean, nil] `true` when a partition filter will be
416
+ # required, `false` otherwise, or `nil` if the object is a reference
417
+ # (see {#reference?}).
418
+ #
419
+ # @!group Attributes
420
+ #
421
+ def require_partition_filter
422
+ return nil if reference?
423
+ ensure_full_data!
424
+ @gapi.require_partition_filter
425
+ end
426
+
427
+ ##
428
+ # Sets whether queries over this table require a partition filter. See
429
+ # [Partitioned
430
+ # Tables](https://cloud.google.com/bigquery/docs/partitioned-tables).
431
+ #
432
+ # If the table is not a full resource representation (see
433
+ # {#resource_full?}), the full representation will be retrieved before
434
+ # the update to comply with ETag-based optimistic concurrency control.
435
+ #
436
+ # @param [Boolean] new_require Whether queries over this table require a
437
+ # partition filter.
438
+ #
439
+ # @example
440
+ # require "google/cloud/bigquery"
441
+ #
442
+ # bigquery = Google::Cloud::Bigquery.new
443
+ # dataset = bigquery.dataset "my_dataset"
444
+ # table = dataset.create_table "my_table" do |t|
445
+ # t.require_partition_filter = true
446
+ # end
447
+ #
448
+ # @!group Attributes
449
+ #
450
+ def require_partition_filter= new_require
451
+ reload! unless resource_full?
452
+ @gapi.require_partition_filter = new_require
453
+ patch_gapi! :require_partition_filter
454
+ end
455
+
456
+ ###
457
+ # Checks if the table is clustered.
458
+ #
459
+ # @see https://cloud.google.com/bigquery/docs/clustered-tables
460
+ # Introduction to Clustered Tables
461
+ #
462
+ # @return [Boolean, nil] `true` when the table is clustered, or
463
+ # `false` otherwise, if the object is a resource (see {#resource?});
464
+ # `nil` if the object is a reference (see {#reference?}).
465
+ #
466
+ # @!group Attributes
467
+ #
468
+ def clustering?
469
+ return nil if reference?
470
+ !@gapi.clustering.nil?
471
+ end
472
+
473
+ ###
474
+ # One or more fields on which data should be clustered. Must be
475
+ # specified with time partitioning, data in the table will be
476
+ # first partitioned and subsequently clustered. The order of the
477
+ # returned fields determines the sort order of the data.
478
+ #
479
+ # See {Table::Updater#clustering_fields=}.
480
+ #
481
+ # @see https://cloud.google.com/bigquery/docs/partitioned-tables
482
+ # Partitioned Tables
483
+ # @see https://cloud.google.com/bigquery/docs/clustered-tables
484
+ # Introduction to Clustered Tables
485
+ # @see https://cloud.google.com/bigquery/docs/creating-clustered-tables
486
+ # Creating and Using Clustered Tables
487
+ #
488
+ # @return [Array<String>, nil] The clustering fields, or `nil` if the
489
+ # table is not clustered or if the table is a reference (see
490
+ # {#reference?}).
491
+ #
492
+ # @!group Attributes
493
+ #
494
+ def clustering_fields
495
+ return nil if reference?
496
+ ensure_full_data!
497
+ @gapi.clustering.fields if clustering?
498
+ end
499
+
500
+ ##
501
+ # The combined Project ID, Dataset ID, and Table ID for this table, in
502
+ # the format specified by the [Legacy SQL Query
503
+ # Reference](https://cloud.google.com/bigquery/query-reference#from)
504
+ # (`project-name:dataset_id.table_id`). This is useful for referencing
505
+ # tables in other projects and datasets. To use this value in queries
506
+ # see {#query_id}.
507
+ #
508
+ # @return [String, nil] The combined ID, or `nil` if the object is a
509
+ # reference (see {#reference?}).
510
+ #
511
+ # @!group Attributes
512
+ #
513
+ def id
514
+ return nil if reference?
515
+ @gapi.id
516
+ end
517
+
518
+ ##
519
+ # The value returned by {#id}, wrapped in backticks (Standard SQL) or s
520
+ # quare brackets (Legacy SQL) to accommodate project IDs
521
+ # containing dashes. Useful in queries.
522
+ #
523
+ # @param [Boolean] standard_sql Specifies whether to use BigQuery's
524
+ # [standard
525
+ # SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/)
526
+ # dialect. Optional. The default value is true.
527
+ # @param [Boolean] legacy_sql Specifies whether to use BigQuery's
528
+ # [legacy
529
+ # SQL](https://cloud.google.com/bigquery/docs/reference/legacy-sql)
530
+ # dialect. Optional. The default value is false.
531
+ #
532
+ # @return [String] The appropriate table ID for use in queries,
533
+ # depending on SQL type.
534
+ #
535
+ # @example
536
+ # require "google/cloud/bigquery"
537
+ #
538
+ # bigquery = Google::Cloud::Bigquery.new
539
+ # dataset = bigquery.dataset "my_dataset"
540
+ # table = dataset.table "my_table"
541
+ #
542
+ # data = bigquery.query "SELECT first_name FROM #{table.query_id}"
543
+ #
544
+ # @!group Attributes
545
+ #
546
+ def query_id standard_sql: nil, legacy_sql: nil
547
+ if Convert.resolve_legacy_sql standard_sql, legacy_sql
548
+ "[#{project_id}:#{dataset_id}.#{table_id}]"
549
+ else
550
+ "`#{project_id}.#{dataset_id}.#{table_id}`"
551
+ end
552
+ end
553
+
554
+ ##
555
+ # The name of the table.
556
+ #
557
+ # @return [String, nil] The friendly name, or `nil` if the object is a
558
+ # reference (see {#reference?}).
559
+ #
560
+ # @!group Attributes
561
+ #
562
+ def name
563
+ return nil if reference?
564
+ @gapi.friendly_name
565
+ end
566
+
567
+ ##
568
+ # Updates the name of the table.
569
+ #
570
+ # If the table is not a full resource representation (see
571
+ # {#resource_full?}), the full representation will be retrieved before
572
+ # the update to comply with ETag-based optimistic concurrency control.
573
+ #
574
+ # @param [String] new_name The new friendly name.
575
+ #
576
+ # @!group Attributes
577
+ #
578
+ def name= new_name
579
+ reload! unless resource_full?
580
+ @gapi.update! friendly_name: new_name
581
+ patch_gapi! :friendly_name
582
+ end
583
+
584
+ ##
585
+ # The ETag hash of the table.
586
+ #
587
+ # @return [String, nil] The ETag hash, or `nil` if the object is a
588
+ # reference (see {#reference?}).
589
+ #
590
+ # @!group Attributes
591
+ #
592
+ def etag
593
+ return nil if reference?
594
+ ensure_full_data!
595
+ @gapi.etag
596
+ end
597
+
598
+ ##
599
+ # A URL that can be used to access the table using the REST API.
600
+ #
601
+ # @return [String, nil] A REST URL for the resource, or `nil` if the
602
+ # object is a reference (see {#reference?}).
603
+ #
604
+ # @!group Attributes
605
+ #
606
+ def api_url
607
+ return nil if reference?
608
+ ensure_full_data!
609
+ @gapi.self_link
610
+ end
611
+
612
+ ##
613
+ # A user-friendly description of the table.
614
+ #
615
+ # @return [String, nil] The description, or `nil` if the object is a
616
+ # reference (see {#reference?}).
617
+ #
618
+ # @!group Attributes
619
+ #
620
+ def description
621
+ return nil if reference?
622
+ ensure_full_data!
623
+ @gapi.description
624
+ end
625
+
626
+ ##
627
+ # Updates the user-friendly description of the table.
628
+ #
629
+ # If the table is not a full resource representation (see
630
+ # {#resource_full?}), the full representation will be retrieved before
631
+ # the update to comply with ETag-based optimistic concurrency control.
632
+ #
633
+ # @param [String] new_description The new user-friendly description.
634
+ #
635
+ # @!group Attributes
636
+ #
637
+ def description= new_description
638
+ reload! unless resource_full?
639
+ @gapi.update! description: new_description
640
+ patch_gapi! :description
641
+ end
642
+
643
+ ##
644
+ # The number of bytes in the table.
645
+ #
646
+ # @return [Integer, nil] The count of bytes in the table, or `nil` if
647
+ # the object is a reference (see {#reference?}).
648
+ #
649
+ # @!group Data
650
+ #
651
+ def bytes_count
652
+ return nil if reference?
653
+ ensure_full_data!
654
+ begin
655
+ Integer @gapi.num_bytes
656
+ rescue StandardError
657
+ nil
658
+ end
659
+ end
660
+
661
+ ##
662
+ # The number of rows in the table.
663
+ #
664
+ # @return [Integer, nil] The count of rows in the table, or `nil` if the
665
+ # object is a reference (see {#reference?}).
666
+ #
667
+ # @!group Data
668
+ #
669
+ def rows_count
670
+ return nil if reference?
671
+ ensure_full_data!
672
+ begin
673
+ Integer @gapi.num_rows
674
+ rescue StandardError
675
+ nil
676
+ end
677
+ end
678
+
679
+ ##
680
+ # The time when this table was created.
681
+ #
682
+ # @return [Time, nil] The creation time, or `nil` if the object is a
683
+ # reference (see {#reference?}).
684
+ #
685
+ # @!group Attributes
686
+ #
687
+ def created_at
688
+ return nil if reference?
689
+ ensure_full_data!
690
+ Convert.millis_to_time @gapi.creation_time
691
+ end
692
+
693
+ ##
694
+ # The time when this table expires.
695
+ # If not present, the table will persist indefinitely.
696
+ # Expired tables will be deleted and their storage reclaimed.
697
+ #
698
+ # @return [Time, nil] The expiration time, or `nil` if not present or
699
+ # the object is a reference (see {#reference?}).
700
+ #
701
+ # @!group Attributes
702
+ #
703
+ def expires_at
704
+ return nil if reference?
705
+ ensure_full_data!
706
+ Convert.millis_to_time @gapi.expiration_time
707
+ end
708
+
709
+ ##
710
+ # The date when this table was last modified.
711
+ #
712
+ # @return [Time, nil] The last modified time, or `nil` if not present or
713
+ # the object is a reference (see {#reference?}).
714
+ #
715
+ # @!group Attributes
716
+ #
717
+ def modified_at
718
+ return nil if reference?
719
+ ensure_full_data!
720
+ Convert.millis_to_time @gapi.last_modified_time
721
+ end
722
+
723
+ ##
724
+ # Checks if the table's type is "TABLE".
725
+ #
726
+ # @return [Boolean, nil] `true` when the type is `TABLE`, `false`
727
+ # otherwise, if the object is a resource (see {#resource?}); `nil` if
728
+ # the object is a reference (see {#reference?}).
729
+ #
730
+ # @!group Attributes
731
+ #
732
+ def table?
733
+ return nil if reference?
734
+ @gapi.type == "TABLE"
735
+ end
736
+
737
+ ##
738
+ # Checks if the table's type is "VIEW", indicating that the table
739
+ # represents a BigQuery view. See {Dataset#create_view}.
740
+ #
741
+ # @return [Boolean, nil] `true` when the type is `VIEW`, `false`
742
+ # otherwise, if the object is a resource (see {#resource?}); `nil` if
743
+ # the object is a reference (see {#reference?}).
744
+ #
745
+ # @!group Attributes
746
+ #
747
+ def view?
748
+ return nil if reference?
749
+ @gapi.type == "VIEW"
750
+ end
751
+
752
+ ##
753
+ # Checks if the table's type is "EXTERNAL", indicating that the table
754
+ # represents an External Data Source. See {#external?} and
755
+ # {External::DataSource}.
756
+ #
757
+ # @return [Boolean, nil] `true` when the type is `EXTERNAL`, `false`
758
+ # otherwise, if the object is a resource (see {#resource?}); `nil` if
759
+ # the object is a reference (see {#reference?}).
760
+ #
761
+ # @!group Attributes
762
+ #
763
+ def external?
764
+ return nil if reference?
765
+ @gapi.type == "EXTERNAL"
766
+ end
767
+
768
+ ##
769
+ # The geographic location where the table should reside. Possible
770
+ # values include `EU` and `US`. The default value is `US`.
771
+ #
772
+ # @return [String, nil] The location code.
773
+ #
774
+ # @!group Attributes
775
+ #
776
+ def location
777
+ return nil if reference?
778
+ ensure_full_data!
779
+ @gapi.location
780
+ end
781
+
782
+ ##
783
+ # A hash of user-provided labels associated with this table. Labels
784
+ # are used to organize and group tables. See [Using
785
+ # Labels](https://cloud.google.com/bigquery/docs/labels).
786
+ #
787
+ # The returned hash is frozen and changes are not allowed. Use
788
+ # {#labels=} to replace the entire hash.
789
+ #
790
+ # @return [Hash<String, String>, nil] A hash containing key/value pairs.
791
+ #
792
+ # @example
793
+ # require "google/cloud/bigquery"
794
+ #
795
+ # bigquery = Google::Cloud::Bigquery.new
796
+ # dataset = bigquery.dataset "my_dataset"
797
+ # table = dataset.table "my_table"
798
+ #
799
+ # labels = table.labels
800
+ # labels["department"] #=> "shipping"
801
+ #
802
+ # @!group Attributes
803
+ #
804
+ def labels
805
+ return nil if reference?
806
+ m = @gapi.labels
807
+ m = m.to_h if m.respond_to? :to_h
808
+ m.dup.freeze
809
+ end
810
+
811
+ ##
812
+ # Updates the hash of user-provided labels associated with this table.
813
+ # Labels are used to organize and group tables. See [Using
814
+ # Labels](https://cloud.google.com/bigquery/docs/labels).
815
+ #
816
+ # If the table is not a full resource representation (see
817
+ # {#resource_full?}), the full representation will be retrieved before
818
+ # the update to comply with ETag-based optimistic concurrency control.
819
+ #
820
+ # @param [Hash<String, String>] labels A hash containing key/value
821
+ # pairs.
822
+ #
823
+ # * Label keys and values can be no longer than 63 characters.
824
+ # * Label keys and values can contain only lowercase letters, numbers,
825
+ # underscores, hyphens, and international characters.
826
+ # * Label keys and values cannot exceed 128 bytes in size.
827
+ # * Label keys must begin with a letter.
828
+ # * Label keys must be unique within a table.
829
+ #
830
+ # @example
831
+ # require "google/cloud/bigquery"
832
+ #
833
+ # bigquery = Google::Cloud::Bigquery.new
834
+ # dataset = bigquery.dataset "my_dataset"
835
+ # table = dataset.table "my_table"
836
+ #
837
+ # table.labels = { "department" => "shipping" }
838
+ #
839
+ # @!group Attributes
840
+ #
841
+ def labels= labels
842
+ reload! unless resource_full?
843
+ @gapi.labels = labels
844
+ patch_gapi! :labels
845
+ end
846
+
847
+ ##
848
+ # Returns the table's schema. If the table is not a view (See {#view?}),
849
+ # this method can also be used to set, replace, or add to the schema by
850
+ # passing a block. See {Schema} for available methods.
851
+ #
852
+ # If the table is not a full resource representation (see
853
+ # {#resource_full?}), the full representation will be retrieved.
854
+ #
855
+ # @param [Boolean] replace Whether to replace the existing schema with
856
+ # the new schema. If `true`, the fields will replace the existing
857
+ # schema. If `false`, the fields will be added to the existing schema.
858
+ # When a table already contains data, schema changes must be additive.
859
+ # Thus, the default value is `false`.
860
+ # When loading from a file this will always replace the schema, no
861
+ # matter what `replace` is set to. You can update the schema (for
862
+ # example, for a table that already contains data) by providing a
863
+ # schema file that includes the existing schema plus any new
864
+ # fields.
865
+ # @yield [schema] a block for setting the schema
866
+ # @yieldparam [Schema] schema the object accepting the schema
867
+ #
868
+ # @return [Google::Cloud::Bigquery::Schema, nil] A frozen schema object.
869
+ #
870
+ # @example
871
+ # require "google/cloud/bigquery"
872
+ #
873
+ # bigquery = Google::Cloud::Bigquery.new
874
+ # dataset = bigquery.dataset "my_dataset"
875
+ # table = dataset.create_table "my_table"
876
+ #
877
+ # table.schema do |schema|
878
+ # schema.string "first_name", mode: :required
879
+ # schema.record "cities_lived", mode: :repeated do |nested_schema|
880
+ # nested_schema.string "place", mode: :required
881
+ # nested_schema.integer "number_of_years", mode: :required
882
+ # end
883
+ # end
884
+ #
885
+ # @example Load the schema from a file
886
+ # require "google/cloud/bigquery"
887
+ #
888
+ # bigquery = Google::Cloud::Bigquery.new
889
+ # dataset = bigquery.dataset "my_dataset"
890
+ # table = dataset.create_table "my_table"
891
+ # table.schema do |schema|
892
+ # schema.load File.open("schema.json")
893
+ # end
894
+ #
895
+ # @!group Attributes
896
+ #
897
+ def schema replace: false
898
+ return nil if reference? && !block_given?
899
+ reload! unless resource_full?
900
+ schema_builder = Schema.from_gapi @gapi.schema
901
+ if block_given?
902
+ schema_builder = Schema.from_gapi if replace
903
+ yield schema_builder
904
+ if schema_builder.changed?
905
+ @gapi.schema = schema_builder.to_gapi
906
+ patch_gapi! :schema
907
+ end
908
+ end
909
+ schema_builder.freeze
910
+ end
911
+
912
+ ##
913
+ # The fields of the table, obtained from its schema.
914
+ #
915
+ # @return [Array<Schema::Field>, nil] An array of field objects.
916
+ #
917
+ # @example
918
+ # require "google/cloud/bigquery"
919
+ #
920
+ # bigquery = Google::Cloud::Bigquery.new
921
+ # dataset = bigquery.dataset "my_dataset"
922
+ # table = dataset.table "my_table"
923
+ #
924
+ # table.fields.each do |field|
925
+ # puts field.name
926
+ # end
927
+ #
928
+ # @!group Attributes
929
+ #
930
+ def fields
931
+ return nil if reference?
932
+ schema.fields
933
+ end
934
+
935
+ ##
936
+ # The names of the columns in the table, obtained from its schema.
937
+ #
938
+ # @return [Array<Symbol>, nil] An array of column names.
939
+ #
940
+ # @example
941
+ # require "google/cloud/bigquery"
942
+ #
943
+ # bigquery = Google::Cloud::Bigquery.new
944
+ # dataset = bigquery.dataset "my_dataset"
945
+ # table = dataset.table "my_table"
946
+ #
947
+ # table.headers.each do |header|
948
+ # puts header
949
+ # end
950
+ #
951
+ # @!group Attributes
952
+ #
953
+ def headers
954
+ return nil if reference?
955
+ schema.headers
956
+ end
957
+
958
+ ##
959
+ # The types of the fields in the table, obtained from its schema.
960
+ # Types use the same format as the optional query parameter types.
961
+ #
962
+ # @return [Hash] A hash with field names as keys, and types as values.
963
+ #
964
+ # @example
965
+ # require "google/cloud/bigquery"
966
+ #
967
+ # bigquery = Google::Cloud::Bigquery.new
968
+ # dataset = bigquery.dataset "my_dataset"
969
+ # table = dataset.table "my_table"
970
+ #
971
+ # table.param_types
972
+ #
973
+ def param_types
974
+ return nil if reference?
975
+ schema.param_types
976
+ end
977
+
978
+ ##
979
+ # The {EncryptionConfiguration} object that represents the custom
980
+ # encryption method used to protect the table. If not set,
981
+ # {Dataset#default_encryption} is used.
982
+ #
983
+ # Present only if the table is using custom encryption.
984
+ #
985
+ # @see https://cloud.google.com/bigquery/docs/customer-managed-encryption
986
+ # Protecting Data with Cloud KMS Keys
987
+ #
988
+ # @return [EncryptionConfiguration, nil] The encryption configuration.
989
+ #
990
+ # @!group Attributes
991
+ #
992
+ def encryption
993
+ return nil if reference?
994
+ ensure_full_data!
995
+ return nil if @gapi.encryption_configuration.nil?
996
+ EncryptionConfiguration.from_gapi(@gapi.encryption_configuration).freeze
997
+ end
998
+
999
+ ##
1000
+ # Set the {EncryptionConfiguration} object that represents the custom
1001
+ # encryption method used to protect the table. If not set,
1002
+ # {Dataset#default_encryption} is used.
1003
+ #
1004
+ # Present only if the table is using custom encryption.
1005
+ #
1006
+ # If the table is not a full resource representation (see
1007
+ # {#resource_full?}), the full representation will be retrieved before
1008
+ # the update to comply with ETag-based optimistic concurrency control.
1009
+ #
1010
+ # @see https://cloud.google.com/bigquery/docs/customer-managed-encryption
1011
+ # Protecting Data with Cloud KMS Keys
1012
+ #
1013
+ # @param [EncryptionConfiguration] value The new encryption config.
1014
+ #
1015
+ # @!group Attributes
1016
+ #
1017
+ def encryption= value
1018
+ reload! unless resource_full?
1019
+ @gapi.encryption_configuration = value.to_gapi
1020
+ patch_gapi! :encryption_configuration
1021
+ end
1022
+
1023
+ ##
1024
+ # The {External::DataSource} (or subclass) object that represents the
1025
+ # external data source that the table represents. Data can be queried
1026
+ # the table, even though the data is not stored in BigQuery. Instead of
1027
+ # loading or streaming the data, this object references the external
1028
+ # data source.
1029
+ #
1030
+ # Present only if the table represents an External Data Source. See
1031
+ # {#external?} and {External::DataSource}.
1032
+ #
1033
+ # @see https://cloud.google.com/bigquery/external-data-sources
1034
+ # Querying External Data Sources
1035
+ #
1036
+ # @return [External::DataSource, nil] The external data source.
1037
+ #
1038
+ # @!group Attributes
1039
+ #
1040
+ def external
1041
+ return nil if reference?
1042
+ ensure_full_data!
1043
+ return nil if @gapi.external_data_configuration.nil?
1044
+ External.from_gapi(@gapi.external_data_configuration).freeze
1045
+ end
1046
+
1047
+ ##
1048
+ # Set the {External::DataSource} (or subclass) object that represents
1049
+ # the external data source that the table represents. Data can be
1050
+ # queried the table, even though the data is not stored in BigQuery.
1051
+ # Instead of loading or streaming the data, this object references the
1052
+ # external data source.
1053
+ #
1054
+ # Use only if the table represents an External Data Source. See
1055
+ # {#external?} and {External::DataSource}.
1056
+ #
1057
+ # If the table is not a full resource representation (see
1058
+ # {#resource_full?}), the full representation will be retrieved before
1059
+ # the update to comply with ETag-based optimistic concurrency control.
1060
+ #
1061
+ # @see https://cloud.google.com/bigquery/external-data-sources
1062
+ # Querying External Data Sources
1063
+ #
1064
+ # @param [External::DataSource] external An external data source.
1065
+ #
1066
+ # @!group Attributes
1067
+ #
1068
+ def external= external
1069
+ reload! unless resource_full?
1070
+ @gapi.external_data_configuration = external.to_gapi
1071
+ patch_gapi! :external_data_configuration
1072
+ end
1073
+
1074
+ ##
1075
+ # A lower-bound estimate of the number of bytes currently in this
1076
+ # table's streaming buffer, if one is present. This field will be absent
1077
+ # if the table is not being streamed to or if there is no data in the
1078
+ # streaming buffer.
1079
+ #
1080
+ # @return [Integer, nil] The estimated number of bytes in the buffer, or
1081
+ # `nil` if not present or the object is a reference (see
1082
+ # {#reference?}).
1083
+ #
1084
+ # @!group Attributes
1085
+ #
1086
+ def buffer_bytes
1087
+ return nil if reference?
1088
+ ensure_full_data!
1089
+ @gapi.streaming_buffer&.estimated_bytes
1090
+ end
1091
+
1092
+ ##
1093
+ # A lower-bound estimate of the number of rows currently in this
1094
+ # table's streaming buffer, if one is present. This field will be absent
1095
+ # if the table is not being streamed to or if there is no data in the
1096
+ # streaming buffer.
1097
+ #
1098
+ # @return [Integer, nil] The estimated number of rows in the buffer, or
1099
+ # `nil` if not present or the object is a reference (see
1100
+ # {#reference?}).
1101
+ #
1102
+ # @!group Attributes
1103
+ #
1104
+ def buffer_rows
1105
+ return nil if reference?
1106
+ ensure_full_data!
1107
+ @gapi.streaming_buffer&.estimated_rows
1108
+ end
1109
+
1110
+ ##
1111
+ # The time of the oldest entry currently in this table's streaming
1112
+ # buffer, if one is present. This field will be absent if the table is
1113
+ # not being streamed to or if there is no data in the streaming buffer.
1114
+ #
1115
+ # @return [Time, nil] The oldest entry time, or `nil` if not present or
1116
+ # the object is a reference (see {#reference?}).
1117
+ #
1118
+ # @!group Attributes
1119
+ #
1120
+ def buffer_oldest_at
1121
+ return nil if reference?
1122
+ ensure_full_data!
1123
+ return nil unless @gapi.streaming_buffer
1124
+ oldest_entry_time = @gapi.streaming_buffer.oldest_entry_time
1125
+ Convert.millis_to_time oldest_entry_time
1126
+ end
1127
+
1128
+ ##
1129
+ # The query that executes each time the view is loaded.
1130
+ #
1131
+ # @return [String] The query that defines the view.
1132
+ #
1133
+ # @!group Attributes
1134
+ #
1135
+ def query
1136
+ @gapi.view&.query
1137
+ end
1138
+
1139
+ ##
1140
+ # Updates the query that executes each time the view is loaded.
1141
+ #
1142
+ # This sets the query using standard SQL. To specify legacy SQL or to
1143
+ # use user-defined function resources use (#set_query) instead.
1144
+ #
1145
+ # @see https://cloud.google.com/bigquery/query-reference BigQuery Query
1146
+ # Reference
1147
+ #
1148
+ # @param [String] new_query The query that defines the view.
1149
+ #
1150
+ # @example
1151
+ # require "google/cloud/bigquery"
1152
+ #
1153
+ # bigquery = Google::Cloud::Bigquery.new
1154
+ # dataset = bigquery.dataset "my_dataset"
1155
+ # view = dataset.table "my_view"
1156
+ #
1157
+ # view.query = "SELECT first_name FROM " \
1158
+ # "`my_project.my_dataset.my_table`"
1159
+ #
1160
+ # @!group Lifecycle
1161
+ #
1162
+ def query= new_query
1163
+ set_query new_query
1164
+ end
1165
+
1166
+ ##
1167
+ # Updates the query that executes each time the view is loaded. Allows
1168
+ # setting of standard vs. legacy SQL and user-defined function
1169
+ # resources.
1170
+ #
1171
+ # @see https://cloud.google.com/bigquery/query-reference BigQuery Query
1172
+ # Reference
1173
+ #
1174
+ # @param [String] query The query that defines the view.
1175
+ # @param [Boolean] standard_sql Specifies whether to use BigQuery's
1176
+ # [standard
1177
+ # SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/)
1178
+ # dialect. Optional. The default value is true.
1179
+ # @param [Boolean] legacy_sql Specifies whether to use BigQuery's
1180
+ # [legacy
1181
+ # SQL](https://cloud.google.com/bigquery/docs/reference/legacy-sql)
1182
+ # dialect. Optional. The default value is false.
1183
+ # @param [Array<String>, String] udfs User-defined function resources
1184
+ # used in a legacy SQL query. May be either a code resource to load from
1185
+ # a Google Cloud Storage URI (`gs://bucket/path`), or an inline resource
1186
+ # that contains code for a user-defined function (UDF). Providing an
1187
+ # inline code resource is equivalent to providing a URI for a file
1188
+ # containing the same code.
1189
+ #
1190
+ # This parameter is used for defining User Defined Function (UDF)
1191
+ # resources only when using legacy SQL. Users of standard SQL should
1192
+ # leverage either DDL (e.g. `CREATE [TEMPORARY] FUNCTION ...`) or the
1193
+ # Routines API to define UDF resources.
1194
+ #
1195
+ # For additional information on migrating, see: [Migrating to
1196
+ # standard SQL - Differences in user-defined JavaScript
1197
+ # functions](https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql#differences_in_user-defined_javascript_functions)
1198
+ #
1199
+ # @example
1200
+ # require "google/cloud/bigquery"
1201
+ #
1202
+ # bigquery = Google::Cloud::Bigquery.new
1203
+ # dataset = bigquery.dataset "my_dataset"
1204
+ # view = dataset.table "my_view"
1205
+ #
1206
+ # view.set_query "SELECT first_name FROM " \
1207
+ # "`my_project.my_dataset.my_table`",
1208
+ # standard_sql: true
1209
+ #
1210
+ # @!group Lifecycle
1211
+ #
1212
+ def set_query query, standard_sql: nil, legacy_sql: nil, udfs: nil
1213
+ use_legacy_sql = Convert.resolve_legacy_sql standard_sql, legacy_sql
1214
+ @gapi.view = Google::Apis::BigqueryV2::ViewDefinition.new(
1215
+ query: query,
1216
+ use_legacy_sql: use_legacy_sql,
1217
+ user_defined_function_resources: udfs_gapi(udfs)
1218
+ )
1219
+ patch_gapi! :view
1220
+ end
1221
+
1222
+ ##
1223
+ # Checks if the view's query is using legacy sql.
1224
+ #
1225
+ # @return [Boolean] `true` when legacy sql is used, `false` otherwise.
1226
+ #
1227
+ # @!group Attributes
1228
+ #
1229
+ def query_legacy_sql?
1230
+ val = @gapi.view.use_legacy_sql
1231
+ return true if val.nil?
1232
+ val
1233
+ end
1234
+
1235
+ ##
1236
+ # Checks if the view's query is using standard sql.
1237
+ #
1238
+ # @return [Boolean] `true` when standard sql is used, `false` otherwise.
1239
+ #
1240
+ # @!group Attributes
1241
+ #
1242
+ def query_standard_sql?
1243
+ !query_legacy_sql?
1244
+ end
1245
+
1246
+ ##
1247
+ # The user-defined function resources used in the view's query. May be
1248
+ # either a code resource to load from a Google Cloud Storage URI
1249
+ # (`gs://bucket/path`), or an inline resource that contains code for a
1250
+ # user-defined function (UDF). Providing an inline code resource is
1251
+ # equivalent to providing a URI for a file containing the same code. See
1252
+ # [User-Defined
1253
+ # Functions](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions).
1254
+ #
1255
+ # @return [Array<String>] An array containing Google Cloud Storage URIs
1256
+ # and/or inline source code.
1257
+ #
1258
+ # @!group Attributes
1259
+ #
1260
+ def query_udfs
1261
+ udfs_gapi = @gapi.view.user_defined_function_resources
1262
+ return [] if udfs_gapi.nil?
1263
+ Array(udfs_gapi).map { |udf| udf.inline_code || udf.resource_uri }
1264
+ end
1265
+
1266
+ ##
1267
+ # Retrieves data from the table.
1268
+ #
1269
+ # If the table is not a full resource representation (see
1270
+ # {#resource_full?}), the full representation will be retrieved before
1271
+ # the data retrieval.
1272
+ #
1273
+ # @param [String] token Page token, returned by a previous call,
1274
+ # identifying the result set.
1275
+ #
1276
+ # @param [Integer] max Maximum number of results to return.
1277
+ # @param [Integer] start Zero-based index of the starting row to read.
1278
+ #
1279
+ # @return [Google::Cloud::Bigquery::Data]
1280
+ #
1281
+ # @example Paginate rows of data: (See {Data#next})
1282
+ # require "google/cloud/bigquery"
1283
+ #
1284
+ # bigquery = Google::Cloud::Bigquery.new
1285
+ # dataset = bigquery.dataset "my_dataset"
1286
+ # table = dataset.table "my_table"
1287
+ #
1288
+ # data = table.data
1289
+ #
1290
+ # # Iterate over the first page of results
1291
+ # data.each do |row|
1292
+ # puts row[:name]
1293
+ # end
1294
+ # # Retrieve the next page of results
1295
+ # data = data.next if data.next?
1296
+ #
1297
+ # @example Retrieve all rows of data: (See {Data#all})
1298
+ # require "google/cloud/bigquery"
1299
+ #
1300
+ # bigquery = Google::Cloud::Bigquery.new
1301
+ # dataset = bigquery.dataset "my_dataset"
1302
+ # table = dataset.table "my_table"
1303
+ #
1304
+ # data = table.data
1305
+ #
1306
+ # data.all do |row|
1307
+ # puts row[:name]
1308
+ # end
1309
+ #
1310
+ # @!group Data
1311
+ #
1312
+ def data token: nil, max: nil, start: nil
1313
+ ensure_service!
1314
+ reload! unless resource_full?
1315
+ data_json = service.list_tabledata dataset_id, table_id, token: token, max: max, start: start
1316
+ Data.from_gapi_json data_json, gapi, nil, service
1317
+ end
1318
+
1319
+ ##
1320
+ # Copies the data from the table to another table using an asynchronous
1321
+ # method. In this method, a {CopyJob} is immediately returned. The
1322
+ # caller may poll the service by repeatedly calling {Job#reload!} and
1323
+ # {Job#done?} to detect when the job is done, or simply block until the
1324
+ # job is done by calling #{Job#wait_until_done!}. See also {#copy}.
1325
+ #
1326
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1327
+ # {CopyJob::Updater#location=} in a block passed to this method. If the
1328
+ # table is a full resource representation (see {#resource_full?}), the
1329
+ # location of the job will be automatically set to the location of the
1330
+ # table.
1331
+ #
1332
+ # @param [Table, String] destination_table The destination for the
1333
+ # copied data. This can also be a string identifier as specified by
1334
+ # the [Standard SQL Query
1335
+ # Reference](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#from-clause)
1336
+ # (`project-name.dataset_id.table_id`) or the [Legacy SQL Query
1337
+ # Reference](https://cloud.google.com/bigquery/query-reference#from)
1338
+ # (`project-name:dataset_id.table_id`). This is useful for referencing
1339
+ # tables in other projects and datasets.
1340
+ # @param [String] create Specifies whether the job is allowed to create
1341
+ # new tables. The default value is `needed`.
1342
+ #
1343
+ # The following values are supported:
1344
+ #
1345
+ # * `needed` - Create the table if it does not exist.
1346
+ # * `never` - The table must already exist. A 'notFound' error is
1347
+ # raised if the table does not exist.
1348
+ # @param [String] write Specifies how to handle data already present in
1349
+ # the destination table. The default value is `empty`.
1350
+ #
1351
+ # The following values are supported:
1352
+ #
1353
+ # * `truncate` - BigQuery overwrites the table data.
1354
+ # * `append` - BigQuery appends the data to the table.
1355
+ # * `empty` - An error will be returned if the destination table
1356
+ # already contains data.
1357
+ # @param [String] job_id A user-defined ID for the copy job. The ID
1358
+ # must contain only letters (a-z, A-Z), numbers (0-9), underscores
1359
+ # (_), or dashes (-). The maximum length is 1,024 characters. If
1360
+ # `job_id` is provided, then `prefix` will not be used.
1361
+ #
1362
+ # See [Generating a job
1363
+ # ID](https://cloud.google.com/bigquery/docs/managing-jobs#generate-jobid).
1364
+ # @param [String] prefix A string, usually human-readable, that will be
1365
+ # prepended to a generated value to produce a unique job ID. For
1366
+ # example, the prefix `daily_import_job_` can be given to generate a
1367
+ # job ID such as `daily_import_job_12vEDtMQ0mbp1Mo5Z7mzAFQJZazh`. The
1368
+ # prefix must contain only letters (a-z, A-Z), numbers (0-9),
1369
+ # underscores (_), or dashes (-). The maximum length of the entire ID
1370
+ # is 1,024 characters. If `job_id` is provided, then `prefix` will not
1371
+ # be used.
1372
+ # @param [Hash] labels A hash of user-provided labels associated with
1373
+ # the job. You can use these to organize and group your jobs. Label
1374
+ # keys and values can be no longer than 63 characters, can only
1375
+ # contain lowercase letters, numeric characters, underscores and
1376
+ # dashes. International characters are allowed. Label values are
1377
+ # optional. Label keys must start with a letter and each label in the
1378
+ # list must have a different key. See [Requirements for
1379
+ # labels](https://cloud.google.com/bigquery/docs/creating-managing-labels#requirements).
1380
+ # @param [Boolean] dryrun If set, don't actually run this job. Behavior
1381
+ # is undefined however for non-query jobs and may result in an error.
1382
+ # Deprecated.
1383
+ #
1384
+ # @yield [job] a job configuration object
1385
+ # @yieldparam [Google::Cloud::Bigquery::CopyJob::Updater] job a job
1386
+ # configuration object for setting additional options.
1387
+ #
1388
+ # @return [Google::Cloud::Bigquery::CopyJob]
1389
+ #
1390
+ # @example
1391
+ # require "google/cloud/bigquery"
1392
+ #
1393
+ # bigquery = Google::Cloud::Bigquery.new
1394
+ # dataset = bigquery.dataset "my_dataset"
1395
+ # table = dataset.table "my_table"
1396
+ # destination_table = dataset.table "my_destination_table"
1397
+ #
1398
+ # copy_job = table.copy_job destination_table
1399
+ #
1400
+ # @example Passing a string identifier for the destination table:
1401
+ # require "google/cloud/bigquery"
1402
+ #
1403
+ # bigquery = Google::Cloud::Bigquery.new
1404
+ # dataset = bigquery.dataset "my_dataset"
1405
+ # table = dataset.table "my_table"
1406
+ #
1407
+ # copy_job = table.copy_job "other-project:other_dataset.other_table"
1408
+ #
1409
+ # copy_job.wait_until_done!
1410
+ # copy_job.done? #=> true
1411
+ #
1412
+ # @!group Data
1413
+ #
1414
+ def copy_job destination_table, create: nil, write: nil, job_id: nil, prefix: nil, labels: nil, dryrun: nil
1415
+ ensure_service!
1416
+ options = { create: create, write: write, dryrun: dryrun, labels: labels, job_id: job_id, prefix: prefix }
1417
+ updater = CopyJob::Updater.from_options(
1418
+ service,
1419
+ table_ref,
1420
+ Service.get_table_ref(destination_table, default_ref: table_ref),
1421
+ options
1422
+ )
1423
+ updater.location = location if location # may be table reference
1424
+
1425
+ yield updater if block_given?
1426
+
1427
+ job_gapi = updater.to_gapi
1428
+ gapi = service.copy_table job_gapi
1429
+ Job.from_gapi gapi, service
1430
+ end
1431
+
1432
+ ##
1433
+ # Copies the data from the table to another table using a synchronous
1434
+ # method that blocks for a response. Timeouts and transient errors are
1435
+ # generally handled as needed to complete the job. See also
1436
+ # {#copy_job}.
1437
+ #
1438
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1439
+ # {CopyJob::Updater#location=} in a block passed to this method. If the
1440
+ # table is a full resource representation (see {#resource_full?}), the
1441
+ # location of the job will be automatically set to the location of the
1442
+ # table.
1443
+ #
1444
+ # @param [Table, String] destination_table The destination for the
1445
+ # copied data. This can also be a string identifier as specified by
1446
+ # the [Standard SQL Query
1447
+ # Reference](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#from-clause)
1448
+ # (`project-name.dataset_id.table_id`) or the [Legacy SQL Query
1449
+ # Reference](https://cloud.google.com/bigquery/query-reference#from)
1450
+ # (`project-name:dataset_id.table_id`). This is useful for referencing
1451
+ # tables in other projects and datasets.
1452
+ # @param [String] create Specifies whether the job is allowed to create
1453
+ # new tables. The default value is `needed`.
1454
+ #
1455
+ # The following values are supported:
1456
+ #
1457
+ # * `needed` - Create the table if it does not exist.
1458
+ # * `never` - The table must already exist. A 'notFound' error is
1459
+ # raised if the table does not exist.
1460
+ # @param [String] write Specifies how to handle data already present in
1461
+ # the destination table. The default value is `empty`.
1462
+ #
1463
+ # The following values are supported:
1464
+ #
1465
+ # * `truncate` - BigQuery overwrites the table data.
1466
+ # * `append` - BigQuery appends the data to the table.
1467
+ # * `empty` - An error will be returned if the destination table
1468
+ # already contains data.
1469
+ # @yield [job] a job configuration object
1470
+ # @yieldparam [Google::Cloud::Bigquery::CopyJob::Updater] job a job
1471
+ # configuration object for setting additional options.
1472
+ #
1473
+ # @return [Boolean] Returns `true` if the copy operation succeeded.
1474
+ #
1475
+ # @example
1476
+ # require "google/cloud/bigquery"
1477
+ #
1478
+ # bigquery = Google::Cloud::Bigquery.new
1479
+ # dataset = bigquery.dataset "my_dataset"
1480
+ # table = dataset.table "my_table"
1481
+ # destination_table = dataset.table "my_destination_table"
1482
+ #
1483
+ # table.copy destination_table
1484
+ #
1485
+ # @example Passing a string identifier for the destination table:
1486
+ # require "google/cloud/bigquery"
1487
+ #
1488
+ # bigquery = Google::Cloud::Bigquery.new
1489
+ # dataset = bigquery.dataset "my_dataset"
1490
+ # table = dataset.table "my_table"
1491
+ #
1492
+ # table.copy "other-project:other_dataset.other_table"
1493
+ #
1494
+ # @!group Data
1495
+ #
1496
+ def copy destination_table, create: nil, write: nil, &block
1497
+ job = copy_job destination_table, create: create, write: write, &block
1498
+ job.wait_until_done!
1499
+ ensure_job_succeeded! job
1500
+ true
1501
+ end
1502
+
1503
+ ##
1504
+ # Extracts the data from the table to a Google Cloud Storage file using
1505
+ # an asynchronous method. In this method, an {ExtractJob} is immediately
1506
+ # returned. The caller may poll the service by repeatedly calling
1507
+ # {Job#reload!} and {Job#done?} to detect when the job is done, or
1508
+ # simply block until the job is done by calling #{Job#wait_until_done!}.
1509
+ # See also {#extract}.
1510
+ #
1511
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1512
+ # {ExtractJob::Updater#location=} in a block passed to this method. If
1513
+ # the table is a full resource representation (see {#resource_full?}),
1514
+ # the location of the job will be automatically set to the location of
1515
+ # the table.
1516
+ #
1517
+ # @see https://cloud.google.com/bigquery/exporting-data-from-bigquery
1518
+ # Exporting Data From BigQuery
1519
+ #
1520
+ # @param [Google::Cloud::Storage::File, String, Array<String>]
1521
+ # extract_url The Google Storage file or file URI pattern(s) to which
1522
+ # BigQuery should extract the table data.
1523
+ # @param [String] format The exported file format. The default value is
1524
+ # `csv`.
1525
+ #
1526
+ # The following values are supported:
1527
+ #
1528
+ # * `csv` - CSV
1529
+ # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
1530
+ # * `avro` - [Avro](http://avro.apache.org/)
1531
+ # @param [String] compression The compression type to use for exported
1532
+ # files. Possible values include `GZIP` and `NONE`. The default value
1533
+ # is `NONE`.
1534
+ # @param [String] delimiter Delimiter to use between fields in the
1535
+ # exported data. Default is <code>,</code>.
1536
+ # @param [Boolean] header Whether to print out a header row in the
1537
+ # results. Default is `true`.
1538
+ # @param [String] job_id A user-defined ID for the extract job. The ID
1539
+ # must contain only letters (a-z, A-Z), numbers (0-9), underscores
1540
+ # (_), or dashes (-). The maximum length is 1,024 characters. If
1541
+ # `job_id` is provided, then `prefix` will not be used.
1542
+ #
1543
+ # See [Generating a job
1544
+ # ID](https://cloud.google.com/bigquery/docs/managing-jobs#generate-jobid).
1545
+ # @param [String] prefix A string, usually human-readable, that will be
1546
+ # prepended to a generated value to produce a unique job ID. For
1547
+ # example, the prefix `daily_import_job_` can be given to generate a
1548
+ # job ID such as `daily_import_job_12vEDtMQ0mbp1Mo5Z7mzAFQJZazh`. The
1549
+ # prefix must contain only letters (a-z, A-Z), numbers (0-9),
1550
+ # underscores (_), or dashes (-). The maximum length of the entire ID
1551
+ # is 1,024 characters. If `job_id` is provided, then `prefix` will not
1552
+ # be used.
1553
+ # @param [Hash] labels A hash of user-provided labels associated with
1554
+ # the job. You can use these to organize and group your jobs. Label
1555
+ # keys and values can be no longer than 63 characters, can only
1556
+ # contain lowercase letters, numeric characters, underscores and
1557
+ # dashes. International characters are allowed. Label values are
1558
+ # optional. Label keys must start with a letter and each label in the
1559
+ # list must have a different key. See [Requirements for
1560
+ # labels](https://cloud.google.com/bigquery/docs/creating-managing-labels#requirements).
1561
+ # @param [Boolean] dryrun If set, don't actually run this job. Behavior
1562
+ # is undefined however for non-query jobs and may result in an error.
1563
+ # Deprecated.
1564
+ #
1565
+ # @yield [job] a job configuration object
1566
+ # @yieldparam [Google::Cloud::Bigquery::ExtractJob::Updater] job a job
1567
+ # configuration object for setting additional options.
1568
+ #
1569
+ # @return [Google::Cloud::Bigquery::ExtractJob]
1570
+ #
1571
+ # @example
1572
+ # require "google/cloud/bigquery"
1573
+ #
1574
+ # bigquery = Google::Cloud::Bigquery.new
1575
+ # dataset = bigquery.dataset "my_dataset"
1576
+ # table = dataset.table "my_table"
1577
+ #
1578
+ # extract_job = table.extract_job "gs://my-bucket/file-name.json",
1579
+ # format: "json"
1580
+ # extract_job.wait_until_done!
1581
+ # extract_job.done? #=> true
1582
+ #
1583
+ # @!group Data
1584
+ #
1585
+ def extract_job extract_url, format: nil, compression: nil, delimiter: nil, header: nil, job_id: nil,
1586
+ prefix: nil, labels: nil, dryrun: nil
1587
+ ensure_service!
1588
+ options = { format: format, compression: compression, delimiter: delimiter, header: header, dryrun: dryrun,
1589
+ job_id: job_id, prefix: prefix, labels: labels }
1590
+ updater = ExtractJob::Updater.from_options service, table_ref, extract_url, options
1591
+ updater.location = location if location # may be table reference
1592
+
1593
+ yield updater if block_given?
1594
+
1595
+ job_gapi = updater.to_gapi
1596
+ gapi = service.extract_table job_gapi
1597
+ Job.from_gapi gapi, service
1598
+ end
1599
+
1600
+ ##
1601
+ # Extracts the data from the table to a Google Cloud Storage file using
1602
+ # a synchronous method that blocks for a response. Timeouts and
1603
+ # transient errors are generally handled as needed to complete the job.
1604
+ # See also {#extract_job}.
1605
+ #
1606
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1607
+ # {ExtractJob::Updater#location=} in a block passed to this method. If
1608
+ # the table is a full resource representation (see {#resource_full?}),
1609
+ # the location of the job will be automatically set to the location of
1610
+ # the table.
1611
+ #
1612
+ # @see https://cloud.google.com/bigquery/exporting-data-from-bigquery
1613
+ # Exporting Data From BigQuery
1614
+ #
1615
+ # @param [Google::Cloud::Storage::File, String, Array<String>]
1616
+ # extract_url The Google Storage file or file URI pattern(s) to which
1617
+ # BigQuery should extract the table data.
1618
+ # @param [String] format The exported file format. The default value is
1619
+ # `csv`.
1620
+ #
1621
+ # The following values are supported:
1622
+ #
1623
+ # * `csv` - CSV
1624
+ # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
1625
+ # * `avro` - [Avro](http://avro.apache.org/)
1626
+ # @param [String] compression The compression type to use for exported
1627
+ # files. Possible values include `GZIP` and `NONE`. The default value
1628
+ # is `NONE`.
1629
+ # @param [String] delimiter Delimiter to use between fields in the
1630
+ # exported data. Default is <code>,</code>.
1631
+ # @param [Boolean] header Whether to print out a header row in the
1632
+ # results. Default is `true`.
1633
+ # @yield [job] a job configuration object
1634
+ # @yieldparam [Google::Cloud::Bigquery::ExtractJob::Updater] job a job
1635
+ # configuration object for setting additional options.
1636
+ #
1637
+ # @return [Boolean] Returns `true` if the extract operation succeeded.
1638
+ #
1639
+ # @example Extract to a JSON file:
1640
+ # require "google/cloud/bigquery"
1641
+ #
1642
+ # bigquery = Google::Cloud::Bigquery.new
1643
+ # dataset = bigquery.dataset "my_dataset"
1644
+ # table = dataset.table "my_table"
1645
+ #
1646
+ # table.extract "gs://my-bucket/file-name.json", format: "json"
1647
+ #
1648
+ # @example Extract to a CSV file, attaching labels to the job:
1649
+ # require "google/cloud/bigquery"
1650
+ #
1651
+ # bigquery = Google::Cloud::Bigquery.new
1652
+ # dataset = bigquery.dataset "my_dataset"
1653
+ # table = dataset.table "my_table"
1654
+ #
1655
+ # table.extract "gs://my-bucket/file-name.csv" do |extract|
1656
+ # extract.labels = { "custom-label" => "custom-value" }
1657
+ # end
1658
+ #
1659
+ # @!group Data
1660
+ #
1661
+ def extract extract_url, format: nil, compression: nil, delimiter: nil, header: nil, &block
1662
+ job = extract_job extract_url,
1663
+ format: format,
1664
+ compression: compression,
1665
+ delimiter: delimiter,
1666
+ header: header,
1667
+ &block
1668
+ job.wait_until_done!
1669
+ ensure_job_succeeded! job
1670
+ true
1671
+ end
1672
+
1673
+ ##
1674
+ # Loads data into the table. You can pass a google-cloud storage file
1675
+ # path or a google-cloud storage file instance. Or, you can upload a
1676
+ # file directly. See [Loading Data with a POST Request](
1677
+ # https://cloud.google.com/bigquery/loading-data-post-request#multipart).
1678
+ #
1679
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1680
+ # {LoadJob::Updater#location=} in a block passed to this method. If the
1681
+ # table is a full resource representation (see {#resource_full?}), the
1682
+ # location of the job will be automatically set to the location of the
1683
+ # table.
1684
+ #
1685
+ # @param [File, Google::Cloud::Storage::File, String, URI,
1686
+ # Array<Google::Cloud::Storage::File, String, URI>] files
1687
+ # A file or the URI of a Google Cloud Storage file, or an Array of
1688
+ # those, containing data to load into the table.
1689
+ # @param [String] format The exported file format. The default value is
1690
+ # `csv`.
1691
+ #
1692
+ # The following values are supported:
1693
+ #
1694
+ # * `csv` - CSV
1695
+ # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
1696
+ # * `avro` - [Avro](http://avro.apache.org/)
1697
+ # * `orc` - [ORC](https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-orc)
1698
+ # * `parquet` - [Parquet](https://parquet.apache.org/)
1699
+ # * `datastore_backup` - Cloud Datastore backup
1700
+ # @param [String] create Specifies whether the job is allowed to create
1701
+ # new tables. The default value is `needed`.
1702
+ #
1703
+ # The following values are supported:
1704
+ #
1705
+ # * `needed` - Create the table if it does not exist.
1706
+ # * `never` - The table must already exist. A 'notFound' error is
1707
+ # raised if the table does not exist.
1708
+ # @param [String] write Specifies how to handle data already present in
1709
+ # the table. The default value is `append`.
1710
+ #
1711
+ # The following values are supported:
1712
+ #
1713
+ # * `truncate` - BigQuery overwrites the table data.
1714
+ # * `append` - BigQuery appends the data to the table.
1715
+ # * `empty` - An error will be returned if the table already contains
1716
+ # data.
1717
+ # @param [Array<String>] projection_fields If the `format` option is set
1718
+ # to `datastore_backup`, indicates which entity properties to load
1719
+ # from a Cloud Datastore backup. Property names are case sensitive and
1720
+ # must be top-level properties. If not set, BigQuery loads all
1721
+ # properties. If any named property isn't found in the Cloud Datastore
1722
+ # backup, an invalid error is returned.
1723
+ # @param [Boolean] jagged_rows Accept rows that are missing trailing
1724
+ # optional columns. The missing values are treated as nulls. If
1725
+ # `false`, records with missing trailing columns are treated as bad
1726
+ # records, and if there are too many bad records, an invalid error is
1727
+ # returned in the job result. The default value is `false`. Only
1728
+ # applicable to CSV, ignored for other formats.
1729
+ # @param [Boolean] quoted_newlines Indicates if BigQuery should allow
1730
+ # quoted data sections that contain newline characters in a CSV file.
1731
+ # The default value is `false`.
1732
+ # @param [Boolean] autodetect Indicates if BigQuery should
1733
+ # automatically infer the options and schema for CSV and JSON sources.
1734
+ # The default value is `false`.
1735
+ # @param [String] encoding The character encoding of the data. The
1736
+ # supported values are `UTF-8` or `ISO-8859-1`. The default value is
1737
+ # `UTF-8`.
1738
+ # @param [String] delimiter Specifices the separator for fields in a CSV
1739
+ # file. BigQuery converts the string to `ISO-8859-1` encoding, and
1740
+ # then uses the first byte of the encoded string to split the data in
1741
+ # its raw, binary state. Default is <code>,</code>.
1742
+ # @param [Boolean] ignore_unknown Indicates if BigQuery should allow
1743
+ # extra values that are not represented in the table schema. If true,
1744
+ # the extra values are ignored. If false, records with extra columns
1745
+ # are treated as bad records, and if there are too many bad records,
1746
+ # an invalid error is returned in the job result. The default value is
1747
+ # `false`.
1748
+ #
1749
+ # The `format` property determines what BigQuery treats as an extra
1750
+ # value:
1751
+ #
1752
+ # * `CSV`: Trailing columns
1753
+ # * `JSON`: Named values that don't match any column names
1754
+ # @param [Integer] max_bad_records The maximum number of bad records
1755
+ # that BigQuery can ignore when running the job. If the number of bad
1756
+ # records exceeds this value, an invalid error is returned in the job
1757
+ # result. The default value is `0`, which requires that all records
1758
+ # are valid.
1759
+ # @param [String] null_marker Specifies a string that represents a null
1760
+ # value in a CSV file. For example, if you specify `\N`, BigQuery
1761
+ # interprets `\N` as a null value when loading a CSV file. The default
1762
+ # value is the empty string. If you set this property to a custom
1763
+ # value, BigQuery throws an error if an empty string is present for
1764
+ # all data types except for STRING and BYTE. For STRING and BYTE
1765
+ # columns, BigQuery interprets the empty string as an empty value.
1766
+ # @param [String] quote The value that is used to quote data sections in
1767
+ # a CSV file. BigQuery converts the string to ISO-8859-1 encoding, and
1768
+ # then uses the first byte of the encoded string to split the data in
1769
+ # its raw, binary state. The default value is a double-quote
1770
+ # <code>"</code>. If your data does not contain quoted sections, set
1771
+ # the property value to an empty string. If your data contains quoted
1772
+ # newline characters, you must also set the allowQuotedNewlines
1773
+ # property to true.
1774
+ # @param [Integer] skip_leading The number of rows at the top of a CSV
1775
+ # file that BigQuery will skip when loading the data. The default
1776
+ # value is `0`. This property is useful if you have header rows in the
1777
+ # file that should be skipped.
1778
+ # @param [String] job_id A user-defined ID for the load job. The ID
1779
+ # must contain only letters (a-z, A-Z), numbers (0-9), underscores
1780
+ # (_), or dashes (-). The maximum length is 1,024 characters. If
1781
+ # `job_id` is provided, then `prefix` will not be used.
1782
+ #
1783
+ # See [Generating a job
1784
+ # ID](https://cloud.google.com/bigquery/docs/managing-jobs#generate-jobid).
1785
+ # @param [String] prefix A string, usually human-readable, that will be
1786
+ # prepended to a generated value to produce a unique job ID. For
1787
+ # example, the prefix `daily_import_job_` can be given to generate a
1788
+ # job ID such as `daily_import_job_12vEDtMQ0mbp1Mo5Z7mzAFQJZazh`. The
1789
+ # prefix must contain only letters (a-z, A-Z), numbers (0-9),
1790
+ # underscores (_), or dashes (-). The maximum length of the entire ID
1791
+ # is 1,024 characters. If `job_id` is provided, then `prefix` will not
1792
+ # be used.
1793
+ # @param [Hash] labels A hash of user-provided labels associated with
1794
+ # the job. You can use these to organize and group your jobs. Label
1795
+ # keys and values can be no longer than 63 characters, can only
1796
+ # contain lowercase letters, numeric characters, underscores and
1797
+ # dashes. International characters are allowed. Label values are
1798
+ # optional. Label keys must start with a letter and each label in the
1799
+ # list must have a different key. See [Requirements for
1800
+ # labels](https://cloud.google.com/bigquery/docs/creating-managing-labels#requirements).
1801
+ # @param [Boolean] dryrun If set, don't actually run this job. Behavior
1802
+ # is undefined however for non-query jobs and may result in an error.
1803
+ # Deprecated.
1804
+ #
1805
+ # @yield [load_job] a block for setting the load job
1806
+ # @yieldparam [LoadJob] load_job the load job object to be updated
1807
+ #
1808
+ # @return [Google::Cloud::Bigquery::LoadJob]
1809
+ #
1810
+ # @example
1811
+ # require "google/cloud/bigquery"
1812
+ #
1813
+ # bigquery = Google::Cloud::Bigquery.new
1814
+ # dataset = bigquery.dataset "my_dataset"
1815
+ # table = dataset.table "my_table"
1816
+ #
1817
+ # load_job = table.load_job "gs://my-bucket/file-name.csv"
1818
+ #
1819
+ # @example Pass a google-cloud-storage `File` instance:
1820
+ # require "google/cloud/bigquery"
1821
+ # require "google/cloud/storage"
1822
+ #
1823
+ # bigquery = Google::Cloud::Bigquery.new
1824
+ # dataset = bigquery.dataset "my_dataset"
1825
+ # table = dataset.table "my_table"
1826
+ #
1827
+ # storage = Google::Cloud::Storage.new
1828
+ # bucket = storage.bucket "my-bucket"
1829
+ # file = bucket.file "file-name.csv"
1830
+ # load_job = table.load_job file
1831
+ #
1832
+ # @example Pass a list of google-cloud-storage files:
1833
+ # require "google/cloud/bigquery"
1834
+ # require "google/cloud/storage"
1835
+ #
1836
+ # bigquery = Google::Cloud::Bigquery.new
1837
+ # dataset = bigquery.dataset "my_dataset"
1838
+ # table = dataset.table "my_table"
1839
+ #
1840
+ # storage = Google::Cloud::Storage.new
1841
+ # bucket = storage.bucket "my-bucket"
1842
+ # file = bucket.file "file-name.csv"
1843
+ # load_job = table.load_job [file, "gs://my-bucket/file-name2.csv"]
1844
+ #
1845
+ # @example Upload a file directly:
1846
+ # require "google/cloud/bigquery"
1847
+ #
1848
+ # bigquery = Google::Cloud::Bigquery.new
1849
+ # dataset = bigquery.dataset "my_dataset"
1850
+ # table = dataset.table "my_table"
1851
+ #
1852
+ # file = File.open "my_data.csv"
1853
+ # load_job = table.load_job file
1854
+ #
1855
+ # @!group Data
1856
+ #
1857
+ def load_job files, format: nil, create: nil, write: nil, projection_fields: nil, jagged_rows: nil,
1858
+ quoted_newlines: nil, encoding: nil, delimiter: nil, ignore_unknown: nil, max_bad_records: nil,
1859
+ quote: nil, skip_leading: nil, job_id: nil, prefix: nil, labels: nil, autodetect: nil,
1860
+ null_marker: nil, dryrun: nil
1861
+ ensure_service!
1862
+
1863
+ updater = load_job_updater format: format, create: create, write: write, projection_fields: projection_fields,
1864
+ jagged_rows: jagged_rows, quoted_newlines: quoted_newlines, encoding: encoding,
1865
+ delimiter: delimiter, ignore_unknown: ignore_unknown,
1866
+ max_bad_records: max_bad_records, quote: quote, skip_leading: skip_leading,
1867
+ dryrun: dryrun, job_id: job_id, prefix: prefix, schema: schema, labels: labels,
1868
+ autodetect: autodetect, null_marker: null_marker
1869
+
1870
+ yield updater if block_given?
1871
+
1872
+ job_gapi = updater.to_gapi
1873
+
1874
+ return load_local files, job_gapi if local_file? files
1875
+ load_storage files, job_gapi
1876
+ end
1877
+
1878
+ ##
1879
+ # Loads data into the table. You can pass a google-cloud storage file
1880
+ # path or a google-cloud storage file instance. Or, you can upload a
1881
+ # file directly. See [Loading Data with a POST Request](
1882
+ # https://cloud.google.com/bigquery/loading-data-post-request#multipart).
1883
+ #
1884
+ # The geographic location for the job ("US", "EU", etc.) can be set via
1885
+ # {LoadJob::Updater#location=} in a block passed to this method. If the
1886
+ # table is a full resource representation (see {#resource_full?}), the
1887
+ # location of the job will be automatically set to the location of the
1888
+ # table.
1889
+ #
1890
+ # @param [File, Google::Cloud::Storage::File, String, URI,
1891
+ # Array<Google::Cloud::Storage::File, String, URI>] files
1892
+ # A file or the URI of a Google Cloud Storage file, or an Array of
1893
+ # those, containing data to load into the table.
1894
+ # @param [String] format The exported file format. The default value is
1895
+ # `csv`.
1896
+ #
1897
+ # The following values are supported:
1898
+ #
1899
+ # * `csv` - CSV
1900
+ # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
1901
+ # * `avro` - [Avro](http://avro.apache.org/)
1902
+ # * `orc` - [ORC](https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-orc)
1903
+ # * `parquet` - [Parquet](https://parquet.apache.org/)
1904
+ # * `datastore_backup` - Cloud Datastore backup
1905
+ # @param [String] create Specifies whether the job is allowed to create
1906
+ # new tables. The default value is `needed`.
1907
+ #
1908
+ # The following values are supported:
1909
+ #
1910
+ # * `needed` - Create the table if it does not exist.
1911
+ # * `never` - The table must already exist. A 'notFound' error is
1912
+ # raised if the table does not exist.
1913
+ # @param [String] write Specifies how to handle data already present in
1914
+ # the table. The default value is `append`.
1915
+ #
1916
+ # The following values are supported:
1917
+ #
1918
+ # * `truncate` - BigQuery overwrites the table data.
1919
+ # * `append` - BigQuery appends the data to the table.
1920
+ # * `empty` - An error will be returned if the table already contains
1921
+ # data.
1922
+ # @param [Array<String>] projection_fields If the `format` option is set
1923
+ # to `datastore_backup`, indicates which entity properties to load
1924
+ # from a Cloud Datastore backup. Property names are case sensitive and
1925
+ # must be top-level properties. If not set, BigQuery loads all
1926
+ # properties. If any named property isn't found in the Cloud Datastore
1927
+ # backup, an invalid error is returned.
1928
+ # @param [Boolean] jagged_rows Accept rows that are missing trailing
1929
+ # optional columns. The missing values are treated as nulls. If
1930
+ # `false`, records with missing trailing columns are treated as bad
1931
+ # records, and if there are too many bad records, an invalid error is
1932
+ # returned in the job result. The default value is `false`. Only
1933
+ # applicable to CSV, ignored for other formats.
1934
+ # @param [Boolean] quoted_newlines Indicates if BigQuery should allow
1935
+ # quoted data sections that contain newline characters in a CSV file.
1936
+ # The default value is `false`.
1937
+ # @param [Boolean] autodetect Indicates if BigQuery should
1938
+ # automatically infer the options and schema for CSV and JSON sources.
1939
+ # The default value is `false`.
1940
+ # @param [String] encoding The character encoding of the data. The
1941
+ # supported values are `UTF-8` or `ISO-8859-1`. The default value is
1942
+ # `UTF-8`.
1943
+ # @param [String] delimiter Specifices the separator for fields in a CSV
1944
+ # file. BigQuery converts the string to `ISO-8859-1` encoding, and
1945
+ # then uses the first byte of the encoded string to split the data in
1946
+ # its raw, binary state. Default is <code>,</code>.
1947
+ # @param [Boolean] ignore_unknown Indicates if BigQuery should allow
1948
+ # extra values that are not represented in the table schema. If true,
1949
+ # the extra values are ignored. If false, records with extra columns
1950
+ # are treated as bad records, and if there are too many bad records,
1951
+ # an invalid error is returned in the job result. The default value is
1952
+ # `false`.
1953
+ #
1954
+ # The `format` property determines what BigQuery treats as an extra
1955
+ # value:
1956
+ #
1957
+ # * `CSV`: Trailing columns
1958
+ # * `JSON`: Named values that don't match any column names
1959
+ # @param [Integer] max_bad_records The maximum number of bad records
1960
+ # that BigQuery can ignore when running the job. If the number of bad
1961
+ # records exceeds this value, an invalid error is returned in the job
1962
+ # result. The default value is `0`, which requires that all records
1963
+ # are valid.
1964
+ # @param [String] null_marker Specifies a string that represents a null
1965
+ # value in a CSV file. For example, if you specify `\N`, BigQuery
1966
+ # interprets `\N` as a null value when loading a CSV file. The default
1967
+ # value is the empty string. If you set this property to a custom
1968
+ # value, BigQuery throws an error if an empty string is present for
1969
+ # all data types except for STRING and BYTE. For STRING and BYTE
1970
+ # columns, BigQuery interprets the empty string as an empty value.
1971
+ # @param [String] quote The value that is used to quote data sections in
1972
+ # a CSV file. BigQuery converts the string to ISO-8859-1 encoding, and
1973
+ # then uses the first byte of the encoded string to split the data in
1974
+ # its raw, binary state. The default value is a double-quote
1975
+ # <code>"</code>. If your data does not contain quoted sections, set
1976
+ # the property value to an empty string. If your data contains quoted
1977
+ # newline characters, you must also set the allowQuotedNewlines
1978
+ # property to true.
1979
+ # @param [Integer] skip_leading The number of rows at the top of a CSV
1980
+ # file that BigQuery will skip when loading the data. The default
1981
+ # value is `0`. This property is useful if you have header rows in the
1982
+ # file that should be skipped.
1983
+ #
1984
+ # @yield [updater] A block for setting the schema of the destination
1985
+ # table and other options for the load job. The schema can be omitted
1986
+ # if the destination table already exists, or if you're loading data
1987
+ # from a Google Cloud Datastore backup.
1988
+ # @yieldparam [Google::Cloud::Bigquery::LoadJob::Updater] updater An
1989
+ # updater to modify the load job and its schema.
1990
+ #
1991
+ # @return [Boolean] Returns `true` if the load job was successful.
1992
+ #
1993
+ # @example
1994
+ # require "google/cloud/bigquery"
1995
+ #
1996
+ # bigquery = Google::Cloud::Bigquery.new
1997
+ # dataset = bigquery.dataset "my_dataset"
1998
+ # table = dataset.table "my_table"
1999
+ #
2000
+ # success = table.load "gs://my-bucket/file-name.csv"
2001
+ #
2002
+ # @example Pass a google-cloud-storage `File` instance:
2003
+ # require "google/cloud/bigquery"
2004
+ # require "google/cloud/storage"
2005
+ #
2006
+ # bigquery = Google::Cloud::Bigquery.new
2007
+ # dataset = bigquery.dataset "my_dataset"
2008
+ # table = dataset.table "my_table"
2009
+ #
2010
+ # storage = Google::Cloud::Storage.new
2011
+ # bucket = storage.bucket "my-bucket"
2012
+ # file = bucket.file "file-name.csv"
2013
+ # success = table.load file
2014
+ #
2015
+ # @example Pass a list of google-cloud-storage files:
2016
+ # require "google/cloud/bigquery"
2017
+ # require "google/cloud/storage"
2018
+ #
2019
+ # bigquery = Google::Cloud::Bigquery.new
2020
+ # dataset = bigquery.dataset "my_dataset"
2021
+ # table = dataset.table "my_table"
2022
+ #
2023
+ # storage = Google::Cloud::Storage.new
2024
+ # bucket = storage.bucket "my-bucket"
2025
+ # file = bucket.file "file-name.csv"
2026
+ # table.load [file, "gs://my-bucket/file-name2.csv"]
2027
+ #
2028
+ # @example Upload a file directly:
2029
+ # require "google/cloud/bigquery"
2030
+ #
2031
+ # bigquery = Google::Cloud::Bigquery.new
2032
+ # dataset = bigquery.dataset "my_dataset"
2033
+ # table = dataset.table "my_table"
2034
+ #
2035
+ # file = File.open "my_data.json"
2036
+ # success = table.load file do |j|
2037
+ # j.format = "newline_delimited_json"
2038
+ # end
2039
+ #
2040
+ # @!group Data
2041
+ #
2042
+ def load files, format: nil, create: nil, write: nil, projection_fields: nil, jagged_rows: nil,
2043
+ quoted_newlines: nil, encoding: nil, delimiter: nil, ignore_unknown: nil, max_bad_records: nil,
2044
+ quote: nil, skip_leading: nil, autodetect: nil, null_marker: nil, &block
2045
+ job = load_job files, format: format, create: create, write: write, projection_fields: projection_fields,
2046
+ jagged_rows: jagged_rows, quoted_newlines: quoted_newlines, encoding: encoding,
2047
+ delimiter: delimiter, ignore_unknown: ignore_unknown, max_bad_records: max_bad_records,
2048
+ quote: quote, skip_leading: skip_leading, autodetect: autodetect,
2049
+ null_marker: null_marker, &block
2050
+
2051
+ job.wait_until_done!
2052
+ ensure_job_succeeded! job
2053
+ true
2054
+ end
2055
+
2056
+ ##
2057
+ # Inserts data into the table for near-immediate querying, without the
2058
+ # need to complete a load operation before the data can appear in query
2059
+ # results.
2060
+ #
2061
+ # Because BigQuery's streaming API is designed for high insertion rates,
2062
+ # modifications to the underlying table metadata are eventually
2063
+ # consistent when interacting with the streaming system. In most cases
2064
+ # metadata changes are propagated within minutes, but during this period
2065
+ # API responses may reflect the inconsistent state of the table.
2066
+ #
2067
+ # @see https://cloud.google.com/bigquery/streaming-data-into-bigquery
2068
+ # Streaming Data Into BigQuery
2069
+ #
2070
+ # @see https://cloud.google.com/bigquery/troubleshooting-errors#metadata-errors-for-streaming-inserts
2071
+ # BigQuery Troubleshooting: Metadata errors for streaming inserts
2072
+ #
2073
+ # @param [Hash, Array<Hash>] rows A hash object or array of hash objects
2074
+ # containing the data. Required.
2075
+ # @param [Array<String|Symbol>, Symbol] insert_ids A unique ID for each row. BigQuery uses this property to
2076
+ # detect duplicate insertion requests on a best-effort basis. For more information, see [data
2077
+ # consistency](https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataconsistency). Optional. If
2078
+ # not provided, the client library will assign a UUID to each row before the request is sent.
2079
+ #
2080
+ # The value `:skip` can be provided to skip the generation of IDs for all rows, or to skip the generation of an
2081
+ # ID for a specific row in the array.
2082
+ # @param [Boolean] skip_invalid Insert all valid rows of a request, even
2083
+ # if invalid rows exist. The default value is `false`, which causes
2084
+ # the entire request to fail if any invalid rows exist.
2085
+ # @param [Boolean] ignore_unknown Accept rows that contain values that
2086
+ # do not match the schema. The unknown values are ignored. Default is
2087
+ # false, which treats unknown values as errors.
2088
+ #
2089
+ # @return [Google::Cloud::Bigquery::InsertResponse]
2090
+ #
2091
+ # @example
2092
+ # require "google/cloud/bigquery"
2093
+ #
2094
+ # bigquery = Google::Cloud::Bigquery.new
2095
+ # dataset = bigquery.dataset "my_dataset"
2096
+ # table = dataset.table "my_table"
2097
+ #
2098
+ # rows = [
2099
+ # { "first_name" => "Alice", "age" => 21 },
2100
+ # { "first_name" => "Bob", "age" => 22 }
2101
+ # ]
2102
+ # table.insert rows
2103
+ #
2104
+ # @example Avoid retrieving the dataset and table with `skip_lookup`:
2105
+ # require "google/cloud/bigquery"
2106
+ #
2107
+ # bigquery = Google::Cloud::Bigquery.new
2108
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
2109
+ # table = dataset.table "my_table", skip_lookup: true
2110
+ #
2111
+ # rows = [
2112
+ # { "first_name" => "Alice", "age" => 21 },
2113
+ # { "first_name" => "Bob", "age" => 22 }
2114
+ # ]
2115
+ # table.insert rows
2116
+ #
2117
+ # @!group Data
2118
+ #
2119
+ def insert rows, insert_ids: nil, skip_invalid: nil, ignore_unknown: nil
2120
+ rows = [rows] if rows.is_a? Hash
2121
+ raise ArgumentError, "No rows provided" if rows.empty?
2122
+
2123
+ insert_ids = Array.new(rows.count) { :skip } if insert_ids == :skip
2124
+ insert_ids = Array insert_ids
2125
+ if insert_ids.count.positive? && insert_ids.count != rows.count
2126
+ raise ArgumentError, "insert_ids must be the same size as rows"
2127
+ end
2128
+
2129
+ ensure_service!
2130
+ options = { skip_invalid: skip_invalid, ignore_unknown: ignore_unknown, insert_ids: insert_ids }
2131
+ gapi = service.insert_tabledata dataset_id, table_id, rows, options
2132
+ InsertResponse.from_gapi rows, gapi
2133
+ end
2134
+
2135
+ ##
2136
+ # Create an asynchronous inserter object used to insert rows in batches.
2137
+ #
2138
+ # @param [Boolean] skip_invalid Insert all valid rows of a request, even
2139
+ # if invalid rows exist. The default value is `false`, which causes
2140
+ # the entire request to fail if any invalid rows exist.
2141
+ # @param [Boolean] ignore_unknown Accept rows that contain values that
2142
+ # do not match the schema. The unknown values are ignored. Default is
2143
+ # false, which treats unknown values as errors.
2144
+ # @attr_reader [Integer] max_bytes The maximum size of rows to be
2145
+ # collected before the batch is published. Default is 10,000,000
2146
+ # (10MB).
2147
+ # @param [Integer] max_rows The maximum number of rows to be collected
2148
+ # before the batch is published. Default is 500.
2149
+ # @attr_reader [Numeric] interval The number of seconds to collect
2150
+ # messages before the batch is published. Default is 10.
2151
+ # @attr_reader [Numeric] threads The number of threads used to insert
2152
+ # batches of rows. Default is 4.
2153
+ # @yield [response] the callback for when a batch of rows is inserted
2154
+ # @yieldparam [Table::AsyncInserter::Result] result the result of the
2155
+ # asynchronous insert
2156
+ #
2157
+ # @return [Table::AsyncInserter] Returns inserter object.
2158
+ #
2159
+ # @example
2160
+ # require "google/cloud/bigquery"
2161
+ #
2162
+ # bigquery = Google::Cloud::Bigquery.new
2163
+ # dataset = bigquery.dataset "my_dataset"
2164
+ # table = dataset.table "my_table"
2165
+ # inserter = table.insert_async do |result|
2166
+ # if result.error?
2167
+ # log_error result.error
2168
+ # else
2169
+ # log_insert "inserted #{result.insert_count} rows " \
2170
+ # "with #{result.error_count} errors"
2171
+ # end
2172
+ # end
2173
+ #
2174
+ # rows = [
2175
+ # { "first_name" => "Alice", "age" => 21 },
2176
+ # { "first_name" => "Bob", "age" => 22 }
2177
+ # ]
2178
+ # inserter.insert rows
2179
+ #
2180
+ # inserter.stop.wait!
2181
+ #
2182
+ def insert_async skip_invalid: nil, ignore_unknown: nil, max_bytes: 10_000_000, max_rows: 500, interval: 10,
2183
+ threads: 4, &block
2184
+ ensure_service!
2185
+
2186
+ AsyncInserter.new self, skip_invalid: skip_invalid, ignore_unknown: ignore_unknown, max_bytes: max_bytes,
2187
+ max_rows: max_rows, interval: interval, threads: threads, &block
2188
+ end
2189
+
2190
+ ##
2191
+ # Permanently deletes the table.
2192
+ #
2193
+ # @return [Boolean] Returns `true` if the table was deleted.
2194
+ #
2195
+ # @example
2196
+ # require "google/cloud/bigquery"
2197
+ #
2198
+ # bigquery = Google::Cloud::Bigquery.new
2199
+ # dataset = bigquery.dataset "my_dataset"
2200
+ # table = dataset.table "my_table"
2201
+ #
2202
+ # table.delete
2203
+ #
2204
+ # @!group Lifecycle
2205
+ #
2206
+ def delete
2207
+ ensure_service!
2208
+ service.delete_table dataset_id, table_id
2209
+ # Set flag for #exists?
2210
+ @exists = false
2211
+ true
2212
+ end
2213
+
2214
+ ##
2215
+ # Reloads the table with current data from the BigQuery service.
2216
+ #
2217
+ # @return [Google::Cloud::Bigquery::Table] Returns the reloaded
2218
+ # table.
2219
+ #
2220
+ # @example Skip retrieving the table from the service, then load it:
2221
+ # require "google/cloud/bigquery"
2222
+ #
2223
+ # bigquery = Google::Cloud::Bigquery.new
2224
+ #
2225
+ # dataset = bigquery.dataset "my_dataset"
2226
+ # table = dataset.table "my_table", skip_lookup: true
2227
+ #
2228
+ # table.reload!
2229
+ #
2230
+ # @!group Lifecycle
2231
+ #
2232
+ def reload!
2233
+ ensure_service!
2234
+ @gapi = service.get_table dataset_id, table_id
2235
+ @reference = nil
2236
+ @exists = nil
2237
+ self
2238
+ end
2239
+ alias refresh! reload!
2240
+
2241
+ ##
2242
+ # Determines whether the table exists in the BigQuery service. The
2243
+ # result is cached locally. To refresh state, set `force` to `true`.
2244
+ #
2245
+ # @param [Boolean] force Force the latest resource representation to be
2246
+ # retrieved from the BigQuery service when `true`. Otherwise the
2247
+ # return value of this method will be memoized to reduce the number of
2248
+ # API calls made to the BigQuery service. The default is `false`.
2249
+ #
2250
+ # @return [Boolean] `true` when the table exists in the BigQuery
2251
+ # service, `false` otherwise.
2252
+ #
2253
+ # @example
2254
+ # require "google/cloud/bigquery"
2255
+ #
2256
+ # bigquery = Google::Cloud::Bigquery.new
2257
+ #
2258
+ # dataset = bigquery.dataset "my_dataset"
2259
+ # table = dataset.table "my_table", skip_lookup: true
2260
+ # table.exists? # true
2261
+ #
2262
+ def exists? force: false
2263
+ return gapi_exists? if force
2264
+ # If we have a value, return it
2265
+ return @exists unless @exists.nil?
2266
+ # Always true if we have a gapi object
2267
+ return true if resource?
2268
+ gapi_exists?
2269
+ end
2270
+
2271
+ ##
2272
+ # Whether the table was created without retrieving the resource
2273
+ # representation from the BigQuery service.
2274
+ #
2275
+ # @return [Boolean] `true` when the table is just a local reference
2276
+ # object, `false` otherwise.
2277
+ #
2278
+ # @example
2279
+ # require "google/cloud/bigquery"
2280
+ #
2281
+ # bigquery = Google::Cloud::Bigquery.new
2282
+ #
2283
+ # dataset = bigquery.dataset "my_dataset"
2284
+ # table = dataset.table "my_table", skip_lookup: true
2285
+ #
2286
+ # table.reference? # true
2287
+ # table.reload!
2288
+ # table.reference? # false
2289
+ #
2290
+ def reference?
2291
+ @gapi.nil?
2292
+ end
2293
+
2294
+ ##
2295
+ # Whether the table was created with a resource representation from
2296
+ # the BigQuery service.
2297
+ #
2298
+ # @return [Boolean] `true` when the table was created with a resource
2299
+ # representation, `false` otherwise.
2300
+ #
2301
+ # @example
2302
+ # require "google/cloud/bigquery"
2303
+ #
2304
+ # bigquery = Google::Cloud::Bigquery.new
2305
+ #
2306
+ # dataset = bigquery.dataset "my_dataset"
2307
+ # table = dataset.table "my_table", skip_lookup: true
2308
+ #
2309
+ # table.resource? # false
2310
+ # table.reload!
2311
+ # table.resource? # true
2312
+ #
2313
+ def resource?
2314
+ !@gapi.nil?
2315
+ end
2316
+
2317
+ ##
2318
+ # Whether the table was created with a partial resource representation
2319
+ # from the BigQuery service by retrieval through {Dataset#tables}.
2320
+ # See [Tables: list
2321
+ # response](https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/list#response)
2322
+ # for the contents of the partial representation. Accessing any
2323
+ # attribute outside of the partial representation will result in loading
2324
+ # the full representation.
2325
+ #
2326
+ # @return [Boolean] `true` when the table was created with a partial
2327
+ # resource representation, `false` otherwise.
2328
+ #
2329
+ # @example
2330
+ # require "google/cloud/bigquery"
2331
+ #
2332
+ # bigquery = Google::Cloud::Bigquery.new
2333
+ #
2334
+ # dataset = bigquery.dataset "my_dataset"
2335
+ # table = dataset.tables.first
2336
+ #
2337
+ # table.resource_partial? # true
2338
+ # table.description # Loads the full resource.
2339
+ # table.resource_partial? # false
2340
+ #
2341
+ def resource_partial?
2342
+ @gapi.is_a? Google::Apis::BigqueryV2::TableList::Table
2343
+ end
2344
+
2345
+ ##
2346
+ # Whether the table was created with a full resource representation
2347
+ # from the BigQuery service.
2348
+ #
2349
+ # @return [Boolean] `true` when the table was created with a full
2350
+ # resource representation, `false` otherwise.
2351
+ #
2352
+ # @example
2353
+ # require "google/cloud/bigquery"
2354
+ #
2355
+ # bigquery = Google::Cloud::Bigquery.new
2356
+ #
2357
+ # dataset = bigquery.dataset "my_dataset"
2358
+ # table = dataset.table "my_table"
2359
+ #
2360
+ # table.resource_full? # true
2361
+ #
2362
+ def resource_full?
2363
+ @gapi.is_a? Google::Apis::BigqueryV2::Table
2364
+ end
2365
+
2366
+ ##
2367
+ # @private New Table from a Google API Client object.
2368
+ def self.from_gapi gapi, service
2369
+ new.tap do |f|
2370
+ f.gapi = gapi
2371
+ f.service = service
2372
+ end
2373
+ end
2374
+
2375
+ ##
2376
+ # @private New lazy Table object without making an HTTP request, for use with the skip_lookup option.
2377
+ def self.new_reference project_id, dataset_id, table_id, service
2378
+ raise ArgumentError, "dataset_id is required" unless dataset_id
2379
+ raise ArgumentError, "table_id is required" unless table_id
2380
+ new.tap do |b|
2381
+ reference_gapi = Google::Apis::BigqueryV2::TableReference.new(
2382
+ project_id: project_id,
2383
+ dataset_id: dataset_id,
2384
+ table_id: table_id
2385
+ )
2386
+ b.service = service
2387
+ b.instance_variable_set :@reference, reference_gapi
2388
+ end
2389
+ end
2390
+
2391
+ ##
2392
+ # @private New lazy Table object from a Google API Client object.
2393
+ def self.new_reference_from_gapi gapi, service
2394
+ new.tap do |b|
2395
+ b.service = service
2396
+ b.instance_variable_set :@reference, gapi
2397
+ end
2398
+ end
2399
+
2400
+ protected
2401
+
2402
+ ##
2403
+ # Raise an error unless an active service is available.
2404
+ def ensure_service!
2405
+ raise "Must have active connection" unless service
2406
+ end
2407
+
2408
+ ##
2409
+ # Ensures the Google::Apis::BigqueryV2::Table object has been loaded
2410
+ # from the service.
2411
+ def ensure_gapi!
2412
+ ensure_service!
2413
+ return unless reference?
2414
+ reload!
2415
+ end
2416
+
2417
+ ##
2418
+ # Fetch gapi and memoize whether resource exists.
2419
+ def gapi_exists?
2420
+ reload!
2421
+ @exists = true
2422
+ rescue Google::Cloud::NotFoundError
2423
+ @exists = false
2424
+ end
2425
+
2426
+ def patch_gapi! *attributes
2427
+ return if attributes.empty?
2428
+ ensure_service!
2429
+ patch_args = Hash[attributes.map { |attr| [attr, @gapi.send(attr)] }]
2430
+ patch_gapi = Google::Apis::BigqueryV2::Table.new patch_args
2431
+ patch_gapi.etag = etag if etag
2432
+ @gapi = service.patch_table dataset_id, table_id, patch_gapi
2433
+
2434
+ # TODO: restore original impl after acceptance test indicates that
2435
+ # service etag bug is fixed
2436
+ reload!
2437
+ end
2438
+
2439
+ def ensure_job_succeeded! job
2440
+ return unless job.failed?
2441
+ begin
2442
+ # raise to activate ruby exception cause handling
2443
+ raise job.gapi_error
2444
+ rescue StandardError => e
2445
+ # wrap Google::Apis::Error with Google::Cloud::Error
2446
+ raise Google::Cloud::Error.from_error(e)
2447
+ end
2448
+ end
2449
+
2450
+ def load_job_gapi table_id, dryrun, job_id: nil, prefix: nil
2451
+ job_ref = service.job_ref_from job_id, prefix
2452
+ Google::Apis::BigqueryV2::Job.new(
2453
+ job_reference: job_ref,
2454
+ configuration: Google::Apis::BigqueryV2::JobConfiguration.new(
2455
+ load: Google::Apis::BigqueryV2::JobConfigurationLoad.new(
2456
+ destination_table: Google::Apis::BigqueryV2::TableReference.new(
2457
+ project_id: @service.project,
2458
+ dataset_id: dataset_id,
2459
+ table_id: table_id
2460
+ )
2461
+ ),
2462
+ dry_run: dryrun
2463
+ )
2464
+ )
2465
+ end
2466
+
2467
+ def load_job_csv_options! job, jagged_rows: nil, quoted_newlines: nil, delimiter: nil, quote: nil,
2468
+ skip_leading: nil, null_marker: nil
2469
+ job.jagged_rows = jagged_rows unless jagged_rows.nil?
2470
+ job.quoted_newlines = quoted_newlines unless quoted_newlines.nil?
2471
+ job.delimiter = delimiter unless delimiter.nil?
2472
+ job.null_marker = null_marker unless null_marker.nil?
2473
+ job.quote = quote unless quote.nil?
2474
+ job.skip_leading = skip_leading unless skip_leading.nil?
2475
+ end
2476
+
2477
+ def load_job_file_options! job, format: nil, projection_fields: nil, jagged_rows: nil, quoted_newlines: nil,
2478
+ encoding: nil, delimiter: nil, ignore_unknown: nil, max_bad_records: nil, quote: nil,
2479
+ skip_leading: nil, null_marker: nil
2480
+ job.format = format unless format.nil?
2481
+ job.projection_fields = projection_fields unless projection_fields.nil?
2482
+ job.encoding = encoding unless encoding.nil?
2483
+ job.ignore_unknown = ignore_unknown unless ignore_unknown.nil?
2484
+ job.max_bad_records = max_bad_records unless max_bad_records.nil?
2485
+ load_job_csv_options! job, jagged_rows: jagged_rows,
2486
+ quoted_newlines: quoted_newlines,
2487
+ delimiter: delimiter,
2488
+ quote: quote,
2489
+ skip_leading: skip_leading,
2490
+ null_marker: null_marker
2491
+ end
2492
+
2493
+ def load_job_updater format: nil, create: nil, write: nil, projection_fields: nil, jagged_rows: nil,
2494
+ quoted_newlines: nil, encoding: nil, delimiter: nil, ignore_unknown: nil,
2495
+ max_bad_records: nil, quote: nil, skip_leading: nil, dryrun: nil, schema: nil, job_id: nil,
2496
+ prefix: nil, labels: nil, autodetect: nil, null_marker: nil
2497
+ new_job = load_job_gapi table_id, dryrun, job_id: job_id, prefix: prefix
2498
+ LoadJob::Updater.new(new_job).tap do |job|
2499
+ job.location = location if location # may be table reference
2500
+ job.create = create unless create.nil?
2501
+ job.write = write unless write.nil?
2502
+ job.schema = schema unless schema.nil?
2503
+ job.autodetect = autodetect unless autodetect.nil?
2504
+ job.labels = labels unless labels.nil?
2505
+ load_job_file_options! job, format: format,
2506
+ projection_fields: projection_fields,
2507
+ jagged_rows: jagged_rows,
2508
+ quoted_newlines: quoted_newlines,
2509
+ encoding: encoding,
2510
+ delimiter: delimiter,
2511
+ ignore_unknown: ignore_unknown,
2512
+ max_bad_records: max_bad_records,
2513
+ quote: quote,
2514
+ skip_leading: skip_leading,
2515
+ null_marker: null_marker
2516
+ end
2517
+ end
2518
+
2519
+ def load_storage urls, job_gapi
2520
+ # Convert to storage URL
2521
+ urls = [urls].flatten.map do |url|
2522
+ if url.respond_to? :to_gs_url
2523
+ url.to_gs_url
2524
+ elsif url.is_a? URI
2525
+ url.to_s
2526
+ else
2527
+ url
2528
+ end
2529
+ end
2530
+
2531
+ unless urls.nil?
2532
+ job_gapi.configuration.load.update! source_uris: urls
2533
+ if job_gapi.configuration.load.source_format.nil?
2534
+ source_format = Convert.derive_source_format_from_list urls
2535
+ job_gapi.configuration.load.source_format = source_format unless source_format.nil?
2536
+ end
2537
+ end
2538
+
2539
+ gapi = service.load_table_gs_url job_gapi
2540
+ Job.from_gapi gapi, service
2541
+ end
2542
+
2543
+ def load_local file, job_gapi
2544
+ path = Pathname(file).to_path
2545
+ if job_gapi.configuration.load.source_format.nil?
2546
+ source_format = Convert.derive_source_format path
2547
+ job_gapi.configuration.load.source_format = source_format unless source_format.nil?
2548
+ end
2549
+
2550
+ gapi = service.load_table_file file, job_gapi
2551
+ Job.from_gapi gapi, service
2552
+ end
2553
+
2554
+ def load_local_or_uri file, updater
2555
+ job_gapi = updater.to_gapi
2556
+ job = if local_file? file
2557
+ load_local file, job_gapi
2558
+ else
2559
+ load_storage file, job_gapi
2560
+ end
2561
+ job
2562
+ end
2563
+
2564
+ def storage_url? files
2565
+ [files].flatten.all? do |file|
2566
+ file.respond_to?(:to_gs_url) ||
2567
+ (file.respond_to?(:to_str) && file.to_str.downcase.start_with?("gs://")) ||
2568
+ (file.is_a?(URI) && file.to_s.downcase.start_with?("gs://"))
2569
+ end
2570
+ end
2571
+
2572
+ def local_file? file
2573
+ ::File.file? file
2574
+ rescue StandardError
2575
+ false
2576
+ end
2577
+
2578
+ ##
2579
+ # Load the complete representation of the table if it has been
2580
+ # only partially loaded by a request to the API list method.
2581
+ def ensure_full_data!
2582
+ reload! unless data_complete?
2583
+ end
2584
+
2585
+ def data_complete?
2586
+ @gapi.is_a? Google::Apis::BigqueryV2::Table
2587
+ end
2588
+
2589
+ ##
2590
+ # Supports views.
2591
+ def udfs_gapi array_or_str
2592
+ return [] if array_or_str.nil?
2593
+ Array(array_or_str).map do |uri_or_code|
2594
+ resource = Google::Apis::BigqueryV2::UserDefinedFunctionResource.new
2595
+ if uri_or_code.start_with? "gs://"
2596
+ resource.resource_uri = uri_or_code
2597
+ else
2598
+ resource.inline_code = uri_or_code
2599
+ end
2600
+ resource
2601
+ end
2602
+ end
2603
+
2604
+ ##
2605
+ # Yielded to a block to accumulate changes for a create request. See {Dataset#create_table}.
2606
+ class Updater < Table
2607
+ ##
2608
+ # @private A list of attributes that were updated.
2609
+ attr_reader :updates
2610
+
2611
+ ##
2612
+ # @private Create an Updater object.
2613
+ def initialize gapi
2614
+ @updates = []
2615
+ @gapi = gapi
2616
+ @schema = nil
2617
+ end
2618
+
2619
+ ##
2620
+ # Sets the field on which to range partition the table. See [Creating and using integer range partitioned
2621
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
2622
+ #
2623
+ # See {Table::Updater#range_partitioning_start=}, {Table::Updater#range_partitioning_interval=} and
2624
+ # {Table::Updater#range_partitioning_end=}.
2625
+ #
2626
+ # You can only set range partitioning when creating a table as in the example below. BigQuery does not allow
2627
+ # you to change partitioning on an existing table.
2628
+ #
2629
+ # @param [String] field The range partition field. The table is partitioned by this
2630
+ # field. The field must be a top-level `NULLABLE/REQUIRED` field. The only supported
2631
+ # type is `INTEGER/INT64`.
2632
+ #
2633
+ # @example
2634
+ # require "google/cloud/bigquery"
2635
+ #
2636
+ # bigquery = Google::Cloud::Bigquery.new
2637
+ # dataset = bigquery.dataset "my_dataset"
2638
+ #
2639
+ # table = dataset.create_table "my_table" do |t|
2640
+ # t.schema do |schema|
2641
+ # schema.integer "my_table_id", mode: :required
2642
+ # schema.string "my_table_data", mode: :required
2643
+ # end
2644
+ # t.range_partitioning_field = "my_table_id"
2645
+ # t.range_partitioning_start = 0
2646
+ # t.range_partitioning_interval = 10
2647
+ # t.range_partitioning_end = 100
2648
+ # end
2649
+ #
2650
+ # @!group Attributes
2651
+ #
2652
+ def range_partitioning_field= field
2653
+ reload! unless resource_full?
2654
+ @gapi.range_partitioning ||= Google::Apis::BigqueryV2::RangePartitioning.new(
2655
+ range: Google::Apis::BigqueryV2::RangePartitioning::Range.new
2656
+ )
2657
+ @gapi.range_partitioning.field = field
2658
+ patch_gapi! :range_partitioning
2659
+ end
2660
+
2661
+ ##
2662
+ # Sets the start of range partitioning, inclusive, for the table. See [Creating and using integer range
2663
+ # partitioned tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
2664
+ #
2665
+ # You can only set range partitioning when creating a table as in the example below. BigQuery does not allow
2666
+ # you to change partitioning on an existing table.
2667
+ #
2668
+ # See {Table::Updater#range_partitioning_field=}, {Table::Updater#range_partitioning_interval=} and
2669
+ # {Table::Updater#range_partitioning_end=}.
2670
+ #
2671
+ # @param [Integer] range_start The start of range partitioning, inclusive.
2672
+ #
2673
+ # @example
2674
+ # require "google/cloud/bigquery"
2675
+ #
2676
+ # bigquery = Google::Cloud::Bigquery.new
2677
+ # dataset = bigquery.dataset "my_dataset"
2678
+ #
2679
+ # table = dataset.create_table "my_table" do |t|
2680
+ # t.schema do |schema|
2681
+ # schema.integer "my_table_id", mode: :required
2682
+ # schema.string "my_table_data", mode: :required
2683
+ # end
2684
+ # t.range_partitioning_field = "my_table_id"
2685
+ # t.range_partitioning_start = 0
2686
+ # t.range_partitioning_interval = 10
2687
+ # t.range_partitioning_end = 100
2688
+ # end
2689
+ #
2690
+ # @!group Attributes
2691
+ #
2692
+ def range_partitioning_start= range_start
2693
+ reload! unless resource_full?
2694
+ @gapi.range_partitioning ||= Google::Apis::BigqueryV2::RangePartitioning.new(
2695
+ range: Google::Apis::BigqueryV2::RangePartitioning::Range.new
2696
+ )
2697
+ @gapi.range_partitioning.range.start = range_start
2698
+ patch_gapi! :range_partitioning
2699
+ end
2700
+
2701
+ ##
2702
+ # Sets width of each interval for data in range partitions. See [Creating and using integer range partitioned
2703
+ # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
2704
+ #
2705
+ # You can only set range partitioning when creating a table as in the example below. BigQuery does not allow
2706
+ # you to change partitioning on an existing table.
2707
+ #
2708
+ # See {Table::Updater#range_partitioning_field=}, {Table::Updater#range_partitioning_start=} and
2709
+ # {Table::Updater#range_partitioning_end=}.
2710
+ #
2711
+ # @param [Integer] range_interval The width of each interval, for data in partitions.
2712
+ #
2713
+ # @example
2714
+ # require "google/cloud/bigquery"
2715
+ #
2716
+ # bigquery = Google::Cloud::Bigquery.new
2717
+ # dataset = bigquery.dataset "my_dataset"
2718
+ #
2719
+ # table = dataset.create_table "my_table" do |t|
2720
+ # t.schema do |schema|
2721
+ # schema.integer "my_table_id", mode: :required
2722
+ # schema.string "my_table_data", mode: :required
2723
+ # end
2724
+ # t.range_partitioning_field = "my_table_id"
2725
+ # t.range_partitioning_start = 0
2726
+ # t.range_partitioning_interval = 10
2727
+ # t.range_partitioning_end = 100
2728
+ # end
2729
+ #
2730
+ # @!group Attributes
2731
+ #
2732
+ def range_partitioning_interval= range_interval
2733
+ reload! unless resource_full?
2734
+ @gapi.range_partitioning ||= Google::Apis::BigqueryV2::RangePartitioning.new(
2735
+ range: Google::Apis::BigqueryV2::RangePartitioning::Range.new
2736
+ )
2737
+ @gapi.range_partitioning.range.interval = range_interval
2738
+ patch_gapi! :range_partitioning
2739
+ end
2740
+
2741
+ ##
2742
+ # Sets the end of range partitioning, exclusive, for the table. See [Creating and using integer range
2743
+ # partitioned tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
2744
+ #
2745
+ # You can only set range partitioning when creating a table as in the example below. BigQuery does not allow
2746
+ # you to change partitioning on an existing table.
2747
+ #
2748
+ # See {Table::Updater#range_partitioning_start=}, {Table::Updater#range_partitioning_interval=} and
2749
+ # {Table::Updater#range_partitioning_field=}.
2750
+ #
2751
+ # @param [Integer] range_end The end of range partitioning, exclusive.
2752
+ #
2753
+ # @example
2754
+ # require "google/cloud/bigquery"
2755
+ #
2756
+ # bigquery = Google::Cloud::Bigquery.new
2757
+ # dataset = bigquery.dataset "my_dataset"
2758
+ #
2759
+ # table = dataset.create_table "my_table" do |t|
2760
+ # t.schema do |schema|
2761
+ # schema.integer "my_table_id", mode: :required
2762
+ # schema.string "my_table_data", mode: :required
2763
+ # end
2764
+ # t.range_partitioning_field = "my_table_id"
2765
+ # t.range_partitioning_start = 0
2766
+ # t.range_partitioning_interval = 10
2767
+ # t.range_partitioning_end = 100
2768
+ # end
2769
+ #
2770
+ # @!group Attributes
2771
+ #
2772
+ def range_partitioning_end= range_end
2773
+ reload! unless resource_full?
2774
+ @gapi.range_partitioning ||= Google::Apis::BigqueryV2::RangePartitioning.new(
2775
+ range: Google::Apis::BigqueryV2::RangePartitioning::Range.new
2776
+ )
2777
+ @gapi.range_partitioning.range.end = range_end
2778
+ patch_gapi! :range_partitioning
2779
+ end
2780
+
2781
+ ##
2782
+ # Sets one or more fields on which data should be clustered. Must be
2783
+ # specified with time-based partitioning, data in the table will be
2784
+ # first partitioned and subsequently clustered.
2785
+ #
2786
+ # Only top-level, non-repeated, simple-type fields are supported. When
2787
+ # you cluster a table using multiple columns, the order of columns you
2788
+ # specify is important. The order of the specified columns determines
2789
+ # the sort order of the data.
2790
+ #
2791
+ # You can only set the clustering fields while creating a table as in
2792
+ # the example below. BigQuery does not allow you to change clustering
2793
+ # on an existing table.
2794
+ #
2795
+ # See {Table#clustering_fields}.
2796
+ #
2797
+ # @see https://cloud.google.com/bigquery/docs/partitioned-tables
2798
+ # Partitioned Tables
2799
+ # @see https://cloud.google.com/bigquery/docs/clustered-tables
2800
+ # Introduction to Clustered Tables
2801
+ # @see https://cloud.google.com/bigquery/docs/creating-clustered-tables
2802
+ # Creating and Using Clustered Tables
2803
+ #
2804
+ # @param [Array<String>] fields The clustering fields. Only top-level,
2805
+ # non-repeated, simple-type fields are supported.
2806
+ #
2807
+ # @example
2808
+ # require "google/cloud/bigquery"
2809
+ #
2810
+ # bigquery = Google::Cloud::Bigquery.new
2811
+ # dataset = bigquery.dataset "my_dataset"
2812
+ # table = dataset.create_table "my_table" do |t|
2813
+ # t.schema do |schema|
2814
+ # schema.timestamp "dob", mode: :required
2815
+ # schema.string "first_name", mode: :required
2816
+ # schema.string "last_name", mode: :required
2817
+ # end
2818
+ # t.time_partitioning_type = "DAY"
2819
+ # t.time_partitioning_field = "dob"
2820
+ # t.clustering_fields = ["last_name", "first_name"]
2821
+ # end
2822
+ #
2823
+ # @!group Attributes
2824
+ #
2825
+ def clustering_fields= fields
2826
+ @gapi.clustering ||= Google::Apis::BigqueryV2::Clustering.new
2827
+ @gapi.clustering.fields = fields
2828
+ patch_gapi! :clustering
2829
+ end
2830
+
2831
+ ##
2832
+ # Returns the table's schema. This method can also be used to set,
2833
+ # replace, or add to the schema by passing a block. See {Schema} for
2834
+ # available methods.
2835
+ #
2836
+ # @param [Boolean] replace Whether to replace the existing schema with
2837
+ # the new schema. If `true`, the fields will replace the existing
2838
+ # schema. If `false`, the fields will be added to the existing
2839
+ # schema. When a table already contains data, schema changes must be
2840
+ # additive. Thus, the default value is `false`.
2841
+ # When loading from a file this will always replace the schema, no
2842
+ # matter what `replace` is set to. You can update the schema (for
2843
+ # example, for a table that already contains data) by providing a
2844
+ # schema file that includes the existing schema plus any new
2845
+ # fields.
2846
+ # @yield [schema] a block for setting the schema
2847
+ # @yieldparam [Schema] schema the object accepting the schema
2848
+ #
2849
+ # @return [Google::Cloud::Bigquery::Schema]
2850
+ #
2851
+ # @example
2852
+ # require "google/cloud/bigquery"
2853
+ #
2854
+ # bigquery = Google::Cloud::Bigquery.new
2855
+ # dataset = bigquery.dataset "my_dataset"
2856
+ # table = dataset.create_table "my_table" do |t|
2857
+ # t.name = "My Table"
2858
+ # t.description = "A description of my table."
2859
+ # t.schema do |s|
2860
+ # s.string "first_name", mode: :required
2861
+ # s.record "cities_lived", mode: :repeated do |r|
2862
+ # r.string "place", mode: :required
2863
+ # r.integer "number_of_years", mode: :required
2864
+ # end
2865
+ # end
2866
+ # end
2867
+ #
2868
+ # @example Load the schema from a file
2869
+ # require "google/cloud/bigquery"
2870
+ #
2871
+ # bigquery = Google::Cloud::Bigquery.new
2872
+ # dataset = bigquery.dataset "my_dataset"
2873
+ # table = dataset.create_table "my_table" do |t|
2874
+ # t.name = "My Table"
2875
+ # t.description = "A description of my table."
2876
+ # t.schema do |s|
2877
+ # s.load File.open("schema.json")
2878
+ # end
2879
+ # end
2880
+ #
2881
+ # @!group Schema
2882
+ #
2883
+ def schema replace: false
2884
+ # Same as Table#schema, but not frozen
2885
+ # TODO: make sure to call ensure_full_data! on Dataset#update
2886
+ @schema ||= Schema.from_gapi @gapi.schema
2887
+ if block_given?
2888
+ @schema = Schema.from_gapi if replace
2889
+ yield @schema
2890
+ check_for_mutated_schema!
2891
+ end
2892
+ # Do not freeze on updater, allow modifications
2893
+ @schema
2894
+ end
2895
+
2896
+ ##
2897
+ # Adds a string field to the schema.
2898
+ #
2899
+ # See {Schema#string}.
2900
+ #
2901
+ # @param [String] name The field name. The name must contain only
2902
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
2903
+ # start with a letter or underscore. The maximum length is 128
2904
+ # characters.
2905
+ # @param [String] description A description of the field.
2906
+ # @param [Symbol] mode The field's mode. The possible values are
2907
+ # `:nullable`, `:required`, and `:repeated`. The default value is
2908
+ # `:nullable`.
2909
+ #
2910
+ # @example
2911
+ # require "google/cloud/bigquery"
2912
+ #
2913
+ # bigquery = Google::Cloud::Bigquery.new
2914
+ # dataset = bigquery.dataset "my_dataset"
2915
+ # table = dataset.create_table "my_table" do |schema|
2916
+ # schema.string "first_name", mode: :required
2917
+ # end
2918
+ #
2919
+ # @!group Schema
2920
+ def string name, description: nil, mode: :nullable
2921
+ schema.string name, description: description, mode: mode
2922
+ end
2923
+
2924
+ ##
2925
+ # Adds an integer field to the schema.
2926
+ #
2927
+ # See {Schema#integer}.
2928
+ #
2929
+ # @param [String] name The field name. The name must contain only
2930
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
2931
+ # start with a letter or underscore. The maximum length is 128
2932
+ # characters.
2933
+ # @param [String] description A description of the field.
2934
+ # @param [Symbol] mode The field's mode. The possible values are
2935
+ # `:nullable`, `:required`, and `:repeated`. The default value is
2936
+ # `:nullable`.
2937
+ #
2938
+ # @example
2939
+ # require "google/cloud/bigquery"
2940
+ #
2941
+ # bigquery = Google::Cloud::Bigquery.new
2942
+ # dataset = bigquery.dataset "my_dataset"
2943
+ # table = dataset.create_table "my_table" do |schema|
2944
+ # schema.integer "age", mode: :required
2945
+ # end
2946
+ #
2947
+ # @!group Schema
2948
+ def integer name, description: nil, mode: :nullable
2949
+ schema.integer name, description: description, mode: mode
2950
+ end
2951
+
2952
+ ##
2953
+ # Adds a floating-point number field to the schema.
2954
+ #
2955
+ # See {Schema#float}.
2956
+ #
2957
+ # @param [String] name The field name. The name must contain only
2958
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
2959
+ # start with a letter or underscore. The maximum length is 128
2960
+ # characters.
2961
+ # @param [String] description A description of the field.
2962
+ # @param [Symbol] mode The field's mode. The possible values are
2963
+ # `:nullable`, `:required`, and `:repeated`. The default value is
2964
+ # `:nullable`.
2965
+ #
2966
+ # @example
2967
+ # require "google/cloud/bigquery"
2968
+ #
2969
+ # bigquery = Google::Cloud::Bigquery.new
2970
+ # dataset = bigquery.dataset "my_dataset"
2971
+ # table = dataset.create_table "my_table" do |schema|
2972
+ # schema.float "price", mode: :required
2973
+ # end
2974
+ #
2975
+ # @!group Schema
2976
+ def float name, description: nil, mode: :nullable
2977
+ schema.float name, description: description, mode: mode
2978
+ end
2979
+
2980
+ ##
2981
+ # Adds a numeric number field to the schema. Numeric is a
2982
+ # fixed-precision numeric type with 38 decimal digits, 9 that follow
2983
+ # the decimal point.
2984
+ #
2985
+ # See {Schema#numeric}
2986
+ #
2987
+ # @param [String] name The field name. The name must contain only
2988
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
2989
+ # start with a letter or underscore. The maximum length is 128
2990
+ # characters.
2991
+ # @param [String] description A description of the field.
2992
+ # @param [Symbol] mode The field's mode. The possible values are
2993
+ # `:nullable`, `:required`, and `:repeated`. The default value is
2994
+ # `:nullable`.
2995
+ #
2996
+ # @example
2997
+ # require "google/cloud/bigquery"
2998
+ #
2999
+ # bigquery = Google::Cloud::Bigquery.new
3000
+ # dataset = bigquery.dataset "my_dataset"
3001
+ # table = dataset.create_table "my_table" do |schema|
3002
+ # schema.numeric "total_cost", mode: :required
3003
+ # end
3004
+ #
3005
+ # @!group Schema
3006
+ def numeric name, description: nil, mode: :nullable
3007
+ schema.numeric name, description: description, mode: mode
3008
+ end
3009
+
3010
+ ##
3011
+ # Adds a boolean field to the schema.
3012
+ #
3013
+ # See {Schema#boolean}.
3014
+ #
3015
+ # @param [String] name The field name. The name must contain only
3016
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3017
+ # start with a letter or underscore. The maximum length is 128
3018
+ # characters.
3019
+ # @param [String] description A description of the field.
3020
+ # @param [Symbol] mode The field's mode. The possible values are
3021
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3022
+ # `:nullable`.
3023
+ #
3024
+ # @example
3025
+ # require "google/cloud/bigquery"
3026
+ #
3027
+ # bigquery = Google::Cloud::Bigquery.new
3028
+ # dataset = bigquery.dataset "my_dataset"
3029
+ # table = dataset.create_table "my_table" do |schema|
3030
+ # schema.boolean "active", mode: :required
3031
+ # end
3032
+ #
3033
+ # @!group Schema
3034
+ def boolean name, description: nil, mode: :nullable
3035
+ schema.boolean name, description: description, mode: mode
3036
+ end
3037
+
3038
+ ##
3039
+ # Adds a bytes field to the schema.
3040
+ #
3041
+ # See {Schema#bytes}.
3042
+ #
3043
+ # @param [String] name The field name. The name must contain only
3044
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3045
+ # start with a letter or underscore. The maximum length is 128
3046
+ # characters.
3047
+ # @param [String] description A description of the field.
3048
+ # @param [Symbol] mode The field's mode. The possible values are
3049
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3050
+ # `:nullable`.
3051
+ #
3052
+ # @example
3053
+ # require "google/cloud/bigquery"
3054
+ #
3055
+ # bigquery = Google::Cloud::Bigquery.new
3056
+ # dataset = bigquery.dataset "my_dataset"
3057
+ # table = dataset.create_table "my_table" do |schema|
3058
+ # schema.bytes "avatar", mode: :required
3059
+ # end
3060
+ #
3061
+ # @!group Schema
3062
+ def bytes name, description: nil, mode: :nullable
3063
+ schema.bytes name, description: description, mode: mode
3064
+ end
3065
+
3066
+ ##
3067
+ # Adds a timestamp field to the schema.
3068
+ #
3069
+ # See {Schema#timestamp}.
3070
+ #
3071
+ # @param [String] name The field name. The name must contain only
3072
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3073
+ # start with a letter or underscore. The maximum length is 128
3074
+ # characters.
3075
+ # @param [String] description A description of the field.
3076
+ # @param [Symbol] mode The field's mode. The possible values are
3077
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3078
+ # `:nullable`.
3079
+ #
3080
+ # @example
3081
+ # require "google/cloud/bigquery"
3082
+ #
3083
+ # bigquery = Google::Cloud::Bigquery.new
3084
+ # dataset = bigquery.dataset "my_dataset"
3085
+ # table = dataset.create_table "my_table" do |schema|
3086
+ # schema.timestamp "creation_date", mode: :required
3087
+ # end
3088
+ #
3089
+ # @!group Schema
3090
+ def timestamp name, description: nil, mode: :nullable
3091
+ schema.timestamp name, description: description, mode: mode
3092
+ end
3093
+
3094
+ ##
3095
+ # Adds a time field to the schema.
3096
+ #
3097
+ # See {Schema#time}.
3098
+ #
3099
+ # @param [String] name The field name. The name must contain only
3100
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3101
+ # start with a letter or underscore. The maximum length is 128
3102
+ # characters.
3103
+ # @param [String] description A description of the field.
3104
+ # @param [Symbol] mode The field's mode. The possible values are
3105
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3106
+ # `:nullable`.
3107
+ #
3108
+ # @example
3109
+ # require "google/cloud/bigquery"
3110
+ #
3111
+ # bigquery = Google::Cloud::Bigquery.new
3112
+ # dataset = bigquery.dataset "my_dataset"
3113
+ # table = dataset.create_table "my_table" do |schema|
3114
+ # schema.time "duration", mode: :required
3115
+ # end
3116
+ #
3117
+ # @!group Schema
3118
+ def time name, description: nil, mode: :nullable
3119
+ schema.time name, description: description, mode: mode
3120
+ end
3121
+
3122
+ ##
3123
+ # Adds a datetime field to the schema.
3124
+ #
3125
+ # See {Schema#datetime}.
3126
+ #
3127
+ # @param [String] name The field name. The name must contain only
3128
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3129
+ # start with a letter or underscore. The maximum length is 128
3130
+ # characters.
3131
+ # @param [String] description A description of the field.
3132
+ # @param [Symbol] mode The field's mode. The possible values are
3133
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3134
+ # `:nullable`.
3135
+ #
3136
+ # @example
3137
+ # require "google/cloud/bigquery"
3138
+ #
3139
+ # bigquery = Google::Cloud::Bigquery.new
3140
+ # dataset = bigquery.dataset "my_dataset"
3141
+ # table = dataset.create_table "my_table" do |schema|
3142
+ # schema.datetime "target_end", mode: :required
3143
+ # end
3144
+ #
3145
+ # @!group Schema
3146
+ def datetime name, description: nil, mode: :nullable
3147
+ schema.datetime name, description: description, mode: mode
3148
+ end
3149
+
3150
+ ##
3151
+ # Adds a date field to the schema.
3152
+ #
3153
+ # See {Schema#date}.
3154
+ #
3155
+ # @param [String] name The field name. The name must contain only
3156
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3157
+ # start with a letter or underscore. The maximum length is 128
3158
+ # characters.
3159
+ # @param [String] description A description of the field.
3160
+ # @param [Symbol] mode The field's mode. The possible values are
3161
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3162
+ # `:nullable`.
3163
+ #
3164
+ # @example
3165
+ # require "google/cloud/bigquery"
3166
+ #
3167
+ # bigquery = Google::Cloud::Bigquery.new
3168
+ # dataset = bigquery.dataset "my_dataset"
3169
+ # table = dataset.create_table "my_table" do |schema|
3170
+ # schema.date "birthday", mode: :required
3171
+ # end
3172
+ #
3173
+ # @!group Schema
3174
+ def date name, description: nil, mode: :nullable
3175
+ schema.date name, description: description, mode: mode
3176
+ end
3177
+
3178
+ ##
3179
+ # Adds a record field to the schema. A block must be passed describing
3180
+ # the nested fields of the record. For more information about nested
3181
+ # and repeated records, see [Loading denormalized, nested, and
3182
+ # repeated data
3183
+ # ](https://cloud.google.com/bigquery/docs/loading-data#loading_denormalized_nested_and_repeated_data).
3184
+ #
3185
+ # See {Schema#record}.
3186
+ #
3187
+ # @param [String] name The field name. The name must contain only
3188
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
3189
+ # start with a letter or underscore. The maximum length is 128
3190
+ # characters.
3191
+ # @param [String] description A description of the field.
3192
+ # @param [Symbol] mode The field's mode. The possible values are
3193
+ # `:nullable`, `:required`, and `:repeated`. The default value is
3194
+ # `:nullable`.
3195
+ # @yield [nested_schema] a block for setting the nested schema
3196
+ # @yieldparam [Schema] nested_schema the object accepting the
3197
+ # nested schema
3198
+ #
3199
+ # @example
3200
+ # require "google/cloud/bigquery"
3201
+ #
3202
+ # bigquery = Google::Cloud::Bigquery.new
3203
+ # dataset = bigquery.dataset "my_dataset"
3204
+ # table = dataset.create_table "my_table" do |schema|
3205
+ # schema.record "cities_lived", mode: :repeated do |cities_lived|
3206
+ # cities_lived.string "place", mode: :required
3207
+ # cities_lived.integer "number_of_years", mode: :required
3208
+ # end
3209
+ # end
3210
+ #
3211
+ # @!group Schema
3212
+ #
3213
+ def record name, description: nil, mode: nil, &block
3214
+ schema.record name, description: description, mode: mode, &block
3215
+ end
3216
+
3217
+ # rubocop:disable Style/MethodDefParentheses
3218
+
3219
+ ##
3220
+ # @raise [RuntimeError] not implemented
3221
+ def data(*)
3222
+ raise "not implemented in #{self.class}"
3223
+ end
3224
+
3225
+ ##
3226
+ # @raise [RuntimeError] not implemented
3227
+ def copy_job(*)
3228
+ raise "not implemented in #{self.class}"
3229
+ end
3230
+
3231
+ ##
3232
+ # @raise [RuntimeError] not implemented
3233
+ def copy(*)
3234
+ raise "not implemented in #{self.class}"
3235
+ end
3236
+
3237
+ ##
3238
+ # @raise [RuntimeError] not implemented
3239
+ def extract_job(*)
3240
+ raise "not implemented in #{self.class}"
3241
+ end
3242
+
3243
+ ##
3244
+ # @raise [RuntimeError] not implemented
3245
+ def extract(*)
3246
+ raise "not implemented in #{self.class}"
3247
+ end
3248
+
3249
+ ##
3250
+ # @raise [RuntimeError] not implemented
3251
+ def load_job(*)
3252
+ raise "not implemented in #{self.class}"
3253
+ end
3254
+
3255
+ ##
3256
+ # @raise [RuntimeError] not implemented
3257
+ def load(*)
3258
+ raise "not implemented in #{self.class}"
3259
+ end
3260
+
3261
+ ##
3262
+ # @raise [RuntimeError] not implemented
3263
+ def insert(*)
3264
+ raise "not implemented in #{self.class}"
3265
+ end
3266
+
3267
+ ##
3268
+ # @raise [RuntimeError] not implemented
3269
+ def insert_async(*)
3270
+ raise "not implemented in #{self.class}"
3271
+ end
3272
+
3273
+ ##
3274
+ # @raise [RuntimeError] not implemented
3275
+ def delete
3276
+ raise "not implemented in #{self.class}"
3277
+ end
3278
+
3279
+ ##
3280
+ # @raise [RuntimeError] not implemented
3281
+ def query_job(*)
3282
+ raise "not implemented in #{self.class}"
3283
+ end
3284
+
3285
+ ##
3286
+ # @raise [RuntimeError] not implemented
3287
+ def query(*)
3288
+ raise "not implemented in #{self.class}"
3289
+ end
3290
+
3291
+ ##
3292
+ # @raise [RuntimeError] not implemented
3293
+ def external(*)
3294
+ raise "not implemented in #{self.class}"
3295
+ end
3296
+
3297
+ ##
3298
+ # @raise [RuntimeError] not implemented
3299
+ def reload!
3300
+ raise "not implemented in #{self.class}"
3301
+ end
3302
+ alias refresh! reload!
3303
+
3304
+ # rubocop:enable Style/MethodDefParentheses
3305
+
3306
+ ##
3307
+ # @private Make sure any access changes are saved
3308
+ def check_for_mutated_schema!
3309
+ return if @schema.nil?
3310
+ return unless @schema.changed?
3311
+ @gapi.schema = @schema.to_gapi
3312
+ patch_gapi! :schema
3313
+ end
3314
+
3315
+ ##
3316
+ # @private
3317
+ def to_gapi
3318
+ check_for_mutated_schema!
3319
+ @gapi
3320
+ end
3321
+
3322
+ protected
3323
+
3324
+ ##
3325
+ # Change to a NOOP
3326
+ def ensure_full_data!
3327
+ # Do nothing because we trust the gapi is full before we get here.
3328
+ end
3329
+
3330
+ ##
3331
+ # Queue up all the updates instead of making them.
3332
+ def patch_gapi! attribute
3333
+ @updates << attribute
3334
+ @updates.uniq!
3335
+ end
3336
+ end
3337
+ end
3338
+ end
3339
+ end
3340
+ end