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,668 @@
1
+ # Copyright 2017 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
+ module Google
17
+ module Cloud
18
+ module Bigquery
19
+ class Schema
20
+ ##
21
+ # # Schema Field
22
+ #
23
+ # The fields of a table schema.
24
+ #
25
+ # @see https://cloud.google.com/bigquery/docs/loading-data#loading_denormalized_nested_and_repeated_data
26
+ # Loading denormalized, nested, and repeated data
27
+ #
28
+ # @example
29
+ # require "google/cloud/bigquery"
30
+ #
31
+ # bigquery = Google::Cloud::Bigquery.new
32
+ # dataset = bigquery.dataset "my_dataset"
33
+ # table = dataset.table "my_table"
34
+ #
35
+ # field = table.schema.field "name"
36
+ # field.required? #=> true
37
+ #
38
+ class Field
39
+ # @private
40
+ MODES = ["NULLABLE", "REQUIRED", "REPEATED"].freeze
41
+
42
+ # @private
43
+ TYPES = ["STRING", "INTEGER", "INT64", "FLOAT", "FLOAT64", "NUMERIC", "BOOLEAN", "BOOL", "BYTES", "TIMESTAMP",
44
+ "TIME", "DATETIME", "DATE", "RECORD", "STRUCT"].freeze
45
+
46
+ ##
47
+ # The name of the field.
48
+ #
49
+ # @return [String] The field name. The name must contain only
50
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
51
+ # start with a letter or underscore. The maximum length is 128
52
+ # characters.
53
+ #
54
+ def name
55
+ @gapi.name
56
+ end
57
+
58
+ ##
59
+ # Updates the name of the field.
60
+ #
61
+ # @param [String] new_name The field name. The name must contain only
62
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
63
+ # start with a letter or underscore. The maximum length is 128
64
+ # characters.
65
+ #
66
+ def name= new_name
67
+ @gapi.update! name: String(new_name)
68
+ end
69
+
70
+ ##
71
+ # The data type of the field.
72
+ #
73
+ # @return [String] The field data type. Possible values include
74
+ # `STRING`, `BYTES`, `INTEGER`, `INT64` (same as `INTEGER`),
75
+ # `FLOAT`, `FLOAT64` (same as `FLOAT`), `NUMERIC`, `BOOLEAN`, `BOOL`
76
+ # (same as `BOOLEAN`), `TIMESTAMP`, `DATE`, `TIME`, `DATETIME`,
77
+ # `RECORD` (where `RECORD` indicates that the field contains a
78
+ # nested schema) or `STRUCT` (same as `RECORD`).
79
+ #
80
+ def type
81
+ @gapi.type
82
+ end
83
+
84
+ ##
85
+ # Updates the data type of the field.
86
+ #
87
+ # @param [String] new_type The data type. Possible values include
88
+ # `STRING`, `BYTES`, `INTEGER`, `INT64` (same as `INTEGER`),
89
+ # `FLOAT`, `FLOAT64` (same as `FLOAT`), `NUMERIC`, `BOOLEAN`, `BOOL`
90
+ # (same as `BOOLEAN`), `TIMESTAMP`, `DATE`, `TIME`, `DATETIME`,
91
+ # `RECORD` (where `RECORD` indicates that the field contains a
92
+ # nested schema) or `STRUCT` (same as `RECORD`).
93
+ #
94
+ def type= new_type
95
+ @gapi.update! type: verify_type(new_type)
96
+ end
97
+
98
+ ##
99
+ # Checks if the type of the field is `NULLABLE`.
100
+ #
101
+ # @return [Boolean] `true` when `NULLABLE`, `false` otherwise.
102
+ #
103
+ def nullable?
104
+ mode == "NULLABLE"
105
+ end
106
+
107
+ ##
108
+ # Checks if the type of the field is `REQUIRED`.
109
+ #
110
+ # @return [Boolean] `true` when `REQUIRED`, `false` otherwise.
111
+ #
112
+ def required?
113
+ mode == "REQUIRED"
114
+ end
115
+
116
+ ##
117
+ # Checks if the type of the field is `REPEATED`.
118
+ #
119
+ # @return [Boolean] `true` when `REPEATED`, `false` otherwise.
120
+ #
121
+ def repeated?
122
+ mode == "REPEATED"
123
+ end
124
+
125
+ ##
126
+ # The description of the field.
127
+ #
128
+ # @return [String] The field description. The maximum length is 1,024
129
+ # characters.
130
+ #
131
+ def description
132
+ @gapi.description
133
+ end
134
+
135
+ ##
136
+ # Updates the description of the field.
137
+ #
138
+ # @param [String] new_description The field description. The maximum
139
+ # length is 1,024 characters.
140
+ #
141
+ def description= new_description
142
+ @gapi.update! description: new_description
143
+ end
144
+
145
+ ##
146
+ # The mode of the field.
147
+ #
148
+ # @return [String] The field mode. Possible values include `NULLABLE`,
149
+ # `REQUIRED` and `REPEATED`. The default value is `NULLABLE`.
150
+ #
151
+ def mode
152
+ @gapi.mode
153
+ end
154
+
155
+ ##
156
+ # Updates the mode of the field.
157
+ #
158
+ # @param [String] new_mode The field mode. Possible values include
159
+ # `NULLABLE`, `REQUIRED` and `REPEATED`. The default value is
160
+ # `NULLABLE`.
161
+ #
162
+ def mode= new_mode
163
+ @gapi.update! mode: verify_mode(new_mode)
164
+ end
165
+
166
+ ##
167
+ # Checks if the type of the field is `STRING`.
168
+ #
169
+ # @return [Boolean] `true` when `STRING`, `false` otherwise.
170
+ #
171
+ def string?
172
+ type == "STRING"
173
+ end
174
+
175
+ ##
176
+ # Checks if the type of the field is `INTEGER`.
177
+ #
178
+ # @return [Boolean] `true` when `INTEGER`, `false` otherwise.
179
+ #
180
+ def integer?
181
+ type == "INTEGER" || type == "INT64"
182
+ end
183
+
184
+ ##
185
+ # Checks if the type of the field is `FLOAT`.
186
+ #
187
+ # @return [Boolean] `true` when `FLOAT`, `false` otherwise.
188
+ #
189
+ def float?
190
+ type == "FLOAT" || type == "FLOAT64"
191
+ end
192
+
193
+ ##
194
+ # Checks if the type of the field is `NUMERIC`.
195
+ #
196
+ # @return [Boolean] `true` when `NUMERIC`, `false` otherwise.
197
+ #
198
+ def numeric?
199
+ type == "NUMERIC"
200
+ end
201
+
202
+ ##
203
+ # Checks if the type of the field is `BOOLEAN`.
204
+ #
205
+ # @return [Boolean] `true` when `BOOLEAN`, `false` otherwise.
206
+ #
207
+ def boolean?
208
+ type == "BOOLEAN" || type == "BOOL"
209
+ end
210
+
211
+ ##
212
+ # Checks if the type of the field is `BYTES`.
213
+ #
214
+ # @return [Boolean] `true` when `BYTES`, `false` otherwise.
215
+ #
216
+ def bytes?
217
+ type == "BYTES"
218
+ end
219
+
220
+ ##
221
+ # Checks if the type of the field is `TIMESTAMP`.
222
+ #
223
+ # @return [Boolean] `true` when `TIMESTAMP`, `false` otherwise.
224
+ #
225
+ def timestamp?
226
+ type == "TIMESTAMP"
227
+ end
228
+
229
+ ##
230
+ # Checks if the type of the field is `TIME`.
231
+ #
232
+ # @return [Boolean] `true` when `TIME`, `false` otherwise.
233
+ #
234
+ def time?
235
+ type == "TIME"
236
+ end
237
+
238
+ ##
239
+ # Checks if the type of the field is `DATETIME`.
240
+ #
241
+ # @return [Boolean] `true` when `DATETIME`, `false` otherwise.
242
+ #
243
+ def datetime?
244
+ type == "DATETIME"
245
+ end
246
+
247
+ ##
248
+ # Checks if the type of the field is `DATE`.
249
+ #
250
+ # @return [Boolean] `true` when `DATE`, `false` otherwise.
251
+ #
252
+ def date?
253
+ type == "DATE"
254
+ end
255
+
256
+ ##
257
+ # Checks if the type of the field is `RECORD`.
258
+ #
259
+ # @return [Boolean] `true` when `RECORD`, `false` otherwise.
260
+ #
261
+ def record?
262
+ type == "RECORD" || type == "STRUCT"
263
+ end
264
+ alias struct? record?
265
+
266
+ ##
267
+ # The nested fields if the type property is set to `RECORD`. Will be
268
+ # empty otherwise.
269
+ #
270
+ # @return [Array<Field>, nil] The nested schema fields if the type
271
+ # is set to `RECORD`.
272
+ #
273
+ def fields
274
+ if frozen?
275
+ Array(@gapi.fields).map { |f| Field.from_gapi(f).freeze }.freeze
276
+ else
277
+ Array(@gapi.fields).map { |f| Field.from_gapi f }
278
+ end
279
+ end
280
+
281
+ ##
282
+ # The names of the nested fields as symbols if the type property is
283
+ # set to `RECORD`. Will be empty otherwise.
284
+ #
285
+ # @return [Array<Symbol>, nil] The names of the nested schema fields
286
+ # if the type is set to `RECORD`.
287
+ #
288
+ def headers
289
+ fields.map(&:name).map(&:to_sym)
290
+ end
291
+
292
+ ##
293
+ # The types of the field, using the same format as the optional query
294
+ # parameter types.
295
+ #
296
+ # The parameter types are one of the following BigQuery type codes:
297
+ #
298
+ # * `:BOOL`
299
+ # * `:INT64`
300
+ # * `:FLOAT64`
301
+ # * `:NUMERIC`
302
+ # * `:STRING`
303
+ # * `:DATETIME`
304
+ # * `:DATE`
305
+ # * `:TIMESTAMP`
306
+ # * `:TIME`
307
+ # * `:BYTES`
308
+ # * `Array` - Lists are specified by providing the type code in an array. For example, an array of integers
309
+ # are specified as `[:INT64]`.
310
+ # * `Hash` - Types for STRUCT values (`Hash` objects) are specified using a `Hash` object, where the keys
311
+ # are the nested field names, and the values are the the nested field types.
312
+ #
313
+ # @return [Symbol, Array, Hash] The type.
314
+ #
315
+ def param_type
316
+ param_type = type.to_sym
317
+ param_type = Hash[fields.map { |field| [field.name.to_sym, field.param_type] }] if record?
318
+ param_type = [param_type] if repeated?
319
+ param_type
320
+ end
321
+
322
+ ##
323
+ # Retrieve a nested field by name, if the type property is
324
+ # set to `RECORD`. Will return `nil` otherwise.
325
+ #
326
+ # @return [Field, nil] The nested schema field object, or `nil`.
327
+ #
328
+ def field name
329
+ f = fields.find { |fld| fld.name == name.to_s }
330
+ return nil if f.nil?
331
+ yield f if block_given?
332
+ f
333
+ end
334
+
335
+ ##
336
+ # Adds a string field to the nested schema of a record field.
337
+ #
338
+ # This can only be called on fields that are of type `RECORD`.
339
+ #
340
+ # @param [String] name The field name. The name must contain only
341
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
342
+ # start with a letter or underscore. The maximum length is 128
343
+ # characters.
344
+ # @param [String] description A description of the field.
345
+ # @param [Symbol] mode The field's mode. The possible values are
346
+ # `:nullable`, `:required`, and `:repeated`. The default value is
347
+ # `:nullable`.
348
+ #
349
+ def string name, description: nil, mode: :nullable
350
+ record_check!
351
+
352
+ add_field name, :string, description: description, mode: mode
353
+ end
354
+
355
+ ##
356
+ # Adds an integer field to the nested schema of a record field.
357
+ #
358
+ # This can only be called on fields that are of type `RECORD`.
359
+ #
360
+ # @param [String] name The field name. The name must contain only
361
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
362
+ # start with a letter or underscore. The maximum length is 128
363
+ # characters.
364
+ # @param [String] description A description of the field.
365
+ # @param [Symbol] mode The field's mode. The possible values are
366
+ # `:nullable`, `:required`, and `:repeated`. The default value is
367
+ # `:nullable`.
368
+ #
369
+ def integer name, description: nil, mode: :nullable
370
+ record_check!
371
+
372
+ add_field name, :integer, description: description, mode: mode
373
+ end
374
+
375
+ ##
376
+ # Adds a floating-point number field to the nested schema of a record
377
+ # field.
378
+ #
379
+ # This can only be called on fields that are of type `RECORD`.
380
+ #
381
+ # @param [String] name The field name. The name must contain only
382
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
383
+ # start with a letter or underscore. The maximum length is 128
384
+ # characters.
385
+ # @param [String] description A description of the field.
386
+ # @param [Symbol] mode The field's mode. The possible values are
387
+ # `:nullable`, `:required`, and `:repeated`. The default value is
388
+ # `:nullable`.
389
+ #
390
+ def float name, description: nil, mode: :nullable
391
+ record_check!
392
+
393
+ add_field name, :float, description: description, mode: mode
394
+ end
395
+
396
+ ##
397
+ # Adds a numeric number field to the schema. Numeric is a
398
+ # fixed-precision numeric type with 38 decimal digits, 9 that follow
399
+ # the decimal point.
400
+ #
401
+ # This can only be called on fields that are of type `RECORD`.
402
+ #
403
+ # @param [String] name The field name. The name must contain only
404
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
405
+ # start with a letter or underscore. The maximum length is 128
406
+ # characters.
407
+ # @param [String] description A description of the field.
408
+ # @param [Symbol] mode The field's mode. The possible values are
409
+ # `:nullable`, `:required`, and `:repeated`. The default value is
410
+ # `:nullable`.
411
+ #
412
+ def numeric name, description: nil, mode: :nullable
413
+ record_check!
414
+
415
+ add_field name, :numeric, description: description, mode: mode
416
+ end
417
+
418
+ ##
419
+ # Adds a boolean field to the nested schema of a record field.
420
+ #
421
+ # This can only be called on fields that are of type `RECORD`.
422
+ #
423
+ # @param [String] name The field name. The name must contain only
424
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
425
+ # start with a letter or underscore. The maximum length is 128
426
+ # characters.
427
+ # @param [String] description A description of the field.
428
+ # @param [Symbol] mode The field's mode. The possible values are
429
+ # `:nullable`, `:required`, and `:repeated`. The default value is
430
+ # `:nullable`.
431
+ #
432
+ def boolean name, description: nil, mode: :nullable
433
+ record_check!
434
+
435
+ add_field name, :boolean, description: description, mode: mode
436
+ end
437
+
438
+ ##
439
+ # Adds a bytes field to the nested schema of a record field.
440
+ #
441
+ # This can only be called on fields that are of type `RECORD`.
442
+ #
443
+ # @param [String] name The field name. The name must contain only
444
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
445
+ # start with a letter or underscore. The maximum length is 128
446
+ # characters.
447
+ # @param [String] description A description of the field.
448
+ # @param [Symbol] mode The field's mode. The possible values are
449
+ # `:nullable`, `:required`, and `:repeated`. The default value is
450
+ # `:nullable`.
451
+ #
452
+ def bytes name, description: nil, mode: :nullable
453
+ record_check!
454
+
455
+ add_field name, :bytes, description: description, mode: mode
456
+ end
457
+
458
+ ##
459
+ # Adds a timestamp field to the nested schema of a record field.
460
+ #
461
+ # This can only be called on fields that are of type `RECORD`.
462
+ #
463
+ # @param [String] name The field name. The name must contain only
464
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
465
+ # start with a letter or underscore. The maximum length is 128
466
+ # characters.
467
+ # @param [String] description A description of the field.
468
+ # @param [Symbol] mode The field's mode. The possible values are
469
+ # `:nullable`, `:required`, and `:repeated`. The default value is
470
+ # `:nullable`.
471
+ #
472
+ def timestamp name, description: nil, mode: :nullable
473
+ record_check!
474
+
475
+ add_field name, :timestamp, description: description, mode: mode
476
+ end
477
+
478
+ ##
479
+ # Adds a time field to the nested schema of a record field.
480
+ #
481
+ # This can only be called on fields that are of type `RECORD`.
482
+ #
483
+ # @param [String] name The field name. The name must contain only
484
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
485
+ # start with a letter or underscore. The maximum length is 128
486
+ # characters.
487
+ # @param [String] description A description of the field.
488
+ # @param [Symbol] mode The field's mode. The possible values are
489
+ # `:nullable`, `:required`, and `:repeated`. The default value is
490
+ # `:nullable`.
491
+ #
492
+ def time name, description: nil, mode: :nullable
493
+ record_check!
494
+
495
+ add_field name, :time, description: description, mode: mode
496
+ end
497
+
498
+ ##
499
+ # Adds a datetime field to the nested schema of a record field.
500
+ #
501
+ # This can only be called on fields that are of type `RECORD`.
502
+ #
503
+ # @param [String] name The field name. The name must contain only
504
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
505
+ # start with a letter or underscore. The maximum length is 128
506
+ # characters.
507
+ # @param [String] description A description of the field.
508
+ # @param [Symbol] mode The field's mode. The possible values are
509
+ # `:nullable`, `:required`, and `:repeated`. The default value is
510
+ # `:nullable`.
511
+ #
512
+ def datetime name, description: nil, mode: :nullable
513
+ record_check!
514
+
515
+ add_field name, :datetime, description: description, mode: mode
516
+ end
517
+
518
+ ##
519
+ # Adds a date field to the nested schema of a record field.
520
+ #
521
+ # This can only be called on fields that are of type `RECORD`.
522
+ #
523
+ # @param [String] name The field name. The name must contain only
524
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
525
+ # start with a letter or underscore. The maximum length is 128
526
+ # characters.
527
+ # @param [String] description A description of the field.
528
+ # @param [Symbol] mode The field's mode. The possible values are
529
+ # `:nullable`, `:required`, and `:repeated`. The default value is
530
+ # `:nullable`.
531
+ #
532
+ def date name, description: nil, mode: :nullable
533
+ record_check!
534
+
535
+ add_field name, :date, description: description, mode: mode
536
+ end
537
+
538
+ ##
539
+ # Adds a record field to the nested schema of a record field. A block
540
+ # must be passed describing the nested fields of the record. For more
541
+ # information about nested and repeated records, see [Preparing Data
542
+ # for BigQuery](https://cloud.google.com/bigquery/docs/loading-data#loading_denormalized_nested_and_repeated_data).
543
+ #
544
+ # This can only be called on fields that are of type `RECORD`.
545
+ #
546
+ # @param [String] name The field name. The name must contain only
547
+ # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
548
+ # start with a letter or underscore. The maximum length is 128
549
+ # characters.
550
+ # @param [String] description A description of the field.
551
+ # @param [Symbol] mode The field's mode. The possible values are
552
+ # `:nullable`, `:required`, and `:repeated`. The default value is
553
+ # `:nullable`.
554
+ # @yield [nested_schema] a block for setting the nested schema
555
+ # @yieldparam [Schema] nested_schema the object accepting the
556
+ # nested schema
557
+ #
558
+ # @example
559
+ # require "google/cloud/bigquery"
560
+ #
561
+ # bigquery = Google::Cloud::Bigquery.new
562
+ # dataset = bigquery.dataset "my_dataset"
563
+ # table = dataset.create_table "my_table"
564
+ #
565
+ # table.schema do |schema|
566
+ # schema.string "first_name", mode: :required
567
+ # schema.record "cities_lived", mode: :repeated do |cities_lived|
568
+ # cities_lived.record "city", mode: :required do |city|
569
+ # city.string "name", mode: :required
570
+ # city.string "country", mode: :required
571
+ # end
572
+ # cities_lived.integer "number_of_years", mode: :required
573
+ # end
574
+ # end
575
+ #
576
+ def record name, description: nil, mode: nil
577
+ record_check!
578
+
579
+ # TODO: do we need to raise if no block was given?
580
+ raise ArgumentError, "a block is required" unless block_given?
581
+
582
+ nested_field = add_field name, :record, description: description, mode: mode
583
+ yield nested_field
584
+ nested_field
585
+ end
586
+
587
+ # @private
588
+ def self.from_gapi gapi
589
+ new.tap do |f|
590
+ f.instance_variable_set :@gapi, gapi
591
+ f.instance_variable_set :@original_json, gapi.to_json
592
+ end
593
+ end
594
+
595
+ # @private
596
+ def to_gapi
597
+ @gapi
598
+ end
599
+
600
+ # @private
601
+ def == other
602
+ return false unless other.is_a? Field
603
+ to_gapi.to_h == other.to_gapi.to_h
604
+ end
605
+
606
+ # @private
607
+ def to_hash
608
+ h = {
609
+ name: name,
610
+ type: type,
611
+ mode: mode
612
+ }
613
+ h[:description] = description if description
614
+ h[:fields] = fields.map(&:to_hash) if record?
615
+ h
616
+ end
617
+
618
+ protected
619
+
620
+ def frozen_check!
621
+ return unless frozen?
622
+ raise ArgumentError, "Cannot modify a frozen field"
623
+ end
624
+
625
+ def record_check!
626
+ return unless type != "RECORD"
627
+ raise ArgumentError,
628
+ "Cannot add fields to a non-RECORD field (#{type})"
629
+ end
630
+
631
+ def add_field name, type, description: nil, mode: :nullable
632
+ frozen_check!
633
+
634
+ new_gapi = Google::Apis::BigqueryV2::TableFieldSchema.new(
635
+ name: String(name),
636
+ type: verify_type(type),
637
+ description: description,
638
+ mode: verify_mode(mode),
639
+ fields: []
640
+ )
641
+
642
+ # Remove any existing field of this name
643
+ @gapi.fields ||= []
644
+ @gapi.fields.reject! { |f| f.name == new_gapi.name }
645
+ # Add to the nested fields
646
+ @gapi.fields << new_gapi
647
+
648
+ # return the public API object
649
+ Field.from_gapi new_gapi
650
+ end
651
+
652
+ def verify_type type
653
+ type = type.to_s.upcase
654
+ raise ArgumentError, "Type '#{type}' not found" unless TYPES.include? type
655
+ type
656
+ end
657
+
658
+ def verify_mode mode
659
+ mode = :nullable if mode.nil?
660
+ mode = mode.to_s.upcase
661
+ raise ArgumentError "Unable to determine mode for '#{mode}'" unless MODES.include? mode
662
+ mode
663
+ end
664
+ end
665
+ end
666
+ end
667
+ end
668
+ end