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,740 @@
1
+ # Copyright 2019 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/model/list"
19
+ require "google/cloud/bigquery/standard_sql"
20
+ require "google/cloud/bigquery/convert"
21
+ require "google/apis/bigquery_v2"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Bigquery
26
+ ##
27
+ # # Model
28
+ #
29
+ # A model in BigQuery ML represents what an ML system has learned from the
30
+ # training data.
31
+ #
32
+ # The following types of models are supported by BigQuery ML:
33
+ #
34
+ # * Linear regression for forecasting; for example, the sales of an item
35
+ # on a given day. Labels are real-valued (they cannot be +/- infinity or
36
+ # NaN).
37
+ # * Binary logistic regression for classification; for example,
38
+ # determining whether a customer will make a purchase. Labels must only
39
+ # have two possible values.
40
+ # * Multiclass logistic regression for classification. These models can be
41
+ # used to predict multiple possible values such as whether an input is
42
+ # "low-value," "medium-value," or "high-value." Labels can have up to 50
43
+ # unique values. In BigQuery ML, multiclass logistic regression training
44
+ # uses a multinomial classifier with a cross entropy loss function.
45
+ # * K-means clustering for data segmentation (beta); for example,
46
+ # identifying customer segments. K-means is an unsupervised learning
47
+ # technique, so model training does not require labels nor split data
48
+ # for training or evaluation.
49
+ #
50
+ # In BigQuery ML, a model can be used with data from multiple BigQuery
51
+ # datasets for training and for prediction.
52
+ #
53
+ # @see https://cloud.google.com/bigquery-ml/docs/bigqueryml-intro
54
+ # Introduction to BigQuery ML
55
+ # @see https://cloud.google.com/bigquery-ml/docs/getting-model-metadata
56
+ # Getting model metadata
57
+ #
58
+ # @example
59
+ # require "google/cloud/bigquery"
60
+ #
61
+ # bigquery = Google::Cloud::Bigquery.new
62
+ # dataset = bigquery.dataset "my_dataset"
63
+ #
64
+ # model = dataset.model "my_model"
65
+ #
66
+ class Model
67
+ ##
68
+ # @private The Service object.
69
+ attr_accessor :service
70
+
71
+ ##
72
+ # @private The Google API Client JSON Hash.
73
+ attr_accessor :gapi_json
74
+
75
+ ##
76
+ # @private A Google API Client Model Reference object.
77
+ attr_reader :reference
78
+
79
+ ##
80
+ # @private Create an empty Model object.
81
+ def initialize
82
+ @service = nil
83
+ @gapi_json = nil
84
+ @reference = nil
85
+ end
86
+
87
+ ##
88
+ # A unique ID for this model.
89
+ #
90
+ # @return [String] The ID must contain only letters (a-z, A-Z), numbers
91
+ # (0-9), or underscores (_). The maximum length is 1,024 characters.
92
+ #
93
+ # @!group Attributes
94
+ #
95
+ def model_id
96
+ return @reference.model_id if reference?
97
+ @gapi_json[:modelReference][:modelId]
98
+ end
99
+
100
+ ##
101
+ # The ID of the `Dataset` containing this model.
102
+ #
103
+ # @return [String] The ID must contain only letters (a-z, A-Z), numbers
104
+ # (0-9), or underscores (_). The maximum length is 1,024 characters.
105
+ #
106
+ # @!group Attributes
107
+ #
108
+ def dataset_id
109
+ return @reference.dataset_id if reference?
110
+ @gapi_json[:modelReference][:datasetId]
111
+ end
112
+
113
+ ##
114
+ # The ID of the `Project` containing this model.
115
+ #
116
+ # @return [String] The project ID.
117
+ #
118
+ # @!group Attributes
119
+ #
120
+ def project_id
121
+ return @reference.project_id if reference?
122
+ @gapi_json[:modelReference][:projectId]
123
+ end
124
+
125
+ ##
126
+ # @private The gapi_json fragment containing the Project ID, Dataset ID,
127
+ # and Model ID.
128
+ #
129
+ # @return [Google::Apis::BigqueryV2::ModelReference]
130
+ #
131
+ def model_ref
132
+ return @reference if reference?
133
+ Google::Apis::BigqueryV2::ModelReference.new(
134
+ project_id: project_id,
135
+ dataset_id: dataset_id,
136
+ model_id: model_id
137
+ )
138
+ end
139
+
140
+ ##
141
+ # Type of the model resource. Expected to be one of the following:
142
+ #
143
+ # * LINEAR_REGRESSION - Linear regression model.
144
+ # * LOGISTIC_REGRESSION - Logistic regression based classification
145
+ # model.
146
+ # * KMEANS - K-means clustering model (beta).
147
+ # * TENSORFLOW - An imported TensorFlow model (beta).
148
+ #
149
+ # @return [String, nil] The model type, or `nil` if the object is a
150
+ # reference (see {#reference?}).
151
+ #
152
+ # @!group Attributes
153
+ #
154
+ def model_type
155
+ return nil if reference?
156
+ @gapi_json[:modelType]
157
+ end
158
+
159
+ ##
160
+ # The name of the model.
161
+ #
162
+ # @return [String, nil] The friendly name, or `nil` if the object is a
163
+ # reference (see {#reference?}).
164
+ #
165
+ # @!group Attributes
166
+ #
167
+ def name
168
+ return nil if reference?
169
+ ensure_full_data!
170
+ @gapi_json[:friendlyName]
171
+ end
172
+
173
+ ##
174
+ # Updates the name of the model.
175
+ #
176
+ # If the model is not a full resource representation (see
177
+ # {#resource_full?}), the full representation will be retrieved before
178
+ # the update to comply with ETag-based optimistic concurrency control.
179
+ #
180
+ # @param [String] new_name The new friendly name.
181
+ #
182
+ # @!group Attributes
183
+ #
184
+ def name= new_name
185
+ ensure_full_data!
186
+ patch_gapi! friendlyName: new_name
187
+ end
188
+
189
+ ##
190
+ # The ETag hash of the model.
191
+ #
192
+ # @return [String, nil] The ETag hash, or `nil` if the object is a
193
+ # reference (see {#reference?}).
194
+ #
195
+ # @!group Attributes
196
+ #
197
+ def etag
198
+ return nil if reference?
199
+ ensure_full_data!
200
+ @gapi_json[:etag]
201
+ end
202
+
203
+ ##
204
+ # A user-friendly description of the model.
205
+ #
206
+ # @return [String, nil] The description, or `nil` if the object is a
207
+ # reference (see {#reference?}).
208
+ #
209
+ # @!group Attributes
210
+ #
211
+ def description
212
+ return nil if reference?
213
+ ensure_full_data!
214
+ @gapi_json[:description]
215
+ end
216
+
217
+ ##
218
+ # Updates the user-friendly description of the model.
219
+ #
220
+ # If the model is not a full resource representation (see
221
+ # {#resource_full?}), the full representation will be retrieved before
222
+ # the update to comply with ETag-based optimistic concurrency control.
223
+ #
224
+ # @param [String] new_description The new user-friendly description.
225
+ #
226
+ # @!group Attributes
227
+ #
228
+ def description= new_description
229
+ ensure_full_data!
230
+ patch_gapi! description: new_description
231
+ end
232
+
233
+ ##
234
+ # The time when this model was created.
235
+ #
236
+ # @return [Time, nil] The creation time, or `nil` if the object is a
237
+ # reference (see {#reference?}).
238
+ #
239
+ # @!group Attributes
240
+ #
241
+ def created_at
242
+ return nil if reference?
243
+ Convert.millis_to_time @gapi_json[:creationTime]
244
+ end
245
+
246
+ ##
247
+ # The date when this model was last modified.
248
+ #
249
+ # @return [Time, nil] The last modified time, or `nil` if not present or
250
+ # the object is a reference (see {#reference?}).
251
+ #
252
+ # @!group Attributes
253
+ #
254
+ def modified_at
255
+ return nil if reference?
256
+ Convert.millis_to_time @gapi_json[:lastModifiedTime]
257
+ end
258
+
259
+ ##
260
+ # The time when this model expires.
261
+ # If not present, the model will persist indefinitely.
262
+ # Expired models will be deleted and their storage reclaimed.
263
+ #
264
+ # @return [Time, nil] The expiration time, or `nil` if not present or
265
+ # the object is a reference (see {#reference?}).
266
+ #
267
+ # @!group Attributes
268
+ #
269
+ def expires_at
270
+ return nil if reference?
271
+ ensure_full_data!
272
+ Convert.millis_to_time @gapi_json[:expirationTime]
273
+ end
274
+
275
+ ##
276
+ # Updates time when this model expires.
277
+ #
278
+ # If the model is not a full resource representation (see
279
+ # {#resource_full?}), the full representation will be retrieved before
280
+ # the update to comply with ETag-based optimistic concurrency control.
281
+ #
282
+ # @param [Integer] new_expires_at The new time when this model expires.
283
+ #
284
+ # @!group Attributes
285
+ #
286
+ def expires_at= new_expires_at
287
+ ensure_full_data!
288
+ new_expires_millis = Convert.time_to_millis new_expires_at
289
+ patch_gapi! expirationTime: new_expires_millis
290
+ end
291
+
292
+ ##
293
+ # The geographic location where the model should reside. Possible
294
+ # values include `EU` and `US`. The default value is `US`.
295
+ #
296
+ # @return [String, nil] The location code.
297
+ #
298
+ # @!group Attributes
299
+ #
300
+ def location
301
+ return nil if reference?
302
+ ensure_full_data!
303
+ @gapi_json[:location]
304
+ end
305
+
306
+ ##
307
+ # A hash of user-provided labels associated with this model. Labels
308
+ # are used to organize and group models. See [Using
309
+ # Labels](https://cloud.google.com/bigquery/docs/labels).
310
+ #
311
+ # The returned hash is frozen and changes are not allowed. Use
312
+ # {#labels=} to replace the entire hash.
313
+ #
314
+ # @return [Hash<String, String>, nil] A hash containing key/value pairs.
315
+ #
316
+ # @example
317
+ # require "google/cloud/bigquery"
318
+ #
319
+ # bigquery = Google::Cloud::Bigquery.new
320
+ # dataset = bigquery.dataset "my_dataset"
321
+ # model = dataset.model "my_model"
322
+ #
323
+ # labels = model.labels
324
+ #
325
+ # @!group Attributes
326
+ #
327
+ def labels
328
+ return nil if reference?
329
+ m = @gapi_json[:labels]
330
+ m = m.to_h if m.respond_to? :to_h
331
+ m.dup.freeze
332
+ end
333
+
334
+ ##
335
+ # Updates the hash of user-provided labels associated with this model.
336
+ # Labels are used to organize and group models. See [Using
337
+ # Labels](https://cloud.google.com/bigquery/docs/labels).
338
+ #
339
+ # If the model is not a full resource representation (see
340
+ # {#resource_full?}), the full representation will be retrieved before
341
+ # the update to comply with ETag-based optimistic concurrency control.
342
+ #
343
+ # @param [Hash<String, String>] new_labels A hash containing key/value
344
+ # pairs.
345
+ #
346
+ # * Label keys and values can be no longer than 63 characters.
347
+ # * Label keys and values can contain only lowercase letters, numbers,
348
+ # underscores, hyphens, and international characters.
349
+ # * Label keys and values cannot exceed 128 bytes in size.
350
+ # * Label keys must begin with a letter.
351
+ # * Label keys must be unique within a model.
352
+ #
353
+ # @example
354
+ # require "google/cloud/bigquery"
355
+ #
356
+ # bigquery = Google::Cloud::Bigquery.new
357
+ # dataset = bigquery.dataset "my_dataset"
358
+ # model = dataset.model "my_model"
359
+ #
360
+ # model.labels = { "env" => "production" }
361
+ #
362
+ # @!group Attributes
363
+ #
364
+ def labels= new_labels
365
+ ensure_full_data!
366
+ patch_gapi! labels: new_labels
367
+ end
368
+
369
+ ##
370
+ # The {EncryptionConfiguration} object that represents the custom
371
+ # encryption method used to protect this model. If not set,
372
+ # {Dataset#default_encryption} is used.
373
+ #
374
+ # Present only if this model is using custom encryption.
375
+ #
376
+ # @see https://cloud.google.com/bigquery/docs/customer-managed-encryption
377
+ # Protecting Data with Cloud KMS Keys
378
+ #
379
+ # @return [EncryptionConfiguration, nil] The encryption configuration.
380
+ #
381
+ # @!group Attributes
382
+ #
383
+ # @example
384
+ # require "google/cloud/bigquery"
385
+ #
386
+ # bigquery = Google::Cloud::Bigquery.new
387
+ # dataset = bigquery.dataset "my_dataset"
388
+ # model = dataset.model "my_model"
389
+ #
390
+ # encrypt_config = model.encryption
391
+ #
392
+ # @!group Attributes
393
+ #
394
+ def encryption
395
+ return nil if reference?
396
+ return nil if @gapi_json[:encryptionConfiguration].nil?
397
+ # We have to create a gapic object from the hash because that is what
398
+ # EncryptionConfiguration is expecing.
399
+ json_cmek = @gapi_json[:encryptionConfiguration].to_json
400
+ gapi_cmek = Google::Apis::BigqueryV2::EncryptionConfiguration.from_json json_cmek
401
+ EncryptionConfiguration.from_gapi(gapi_cmek).freeze
402
+ end
403
+
404
+ ##
405
+ # Set the {EncryptionConfiguration} object that represents the custom
406
+ # encryption method used to protect this model. If not set,
407
+ # {Dataset#default_encryption} is used.
408
+ #
409
+ # Present only if this model is using custom encryption.
410
+ #
411
+ # If the model is not a full resource representation (see
412
+ # {#resource_full?}), the full representation will be retrieved before
413
+ # the update to comply with ETag-based optimistic concurrency control.
414
+ #
415
+ # @see https://cloud.google.com/bigquery/docs/customer-managed-encryption
416
+ # Protecting Data with Cloud KMS Keys
417
+ #
418
+ # @param [EncryptionConfiguration] value The new encryption config.
419
+ #
420
+ # @example
421
+ # require "google/cloud/bigquery"
422
+ #
423
+ # bigquery = Google::Cloud::Bigquery.new
424
+ # dataset = bigquery.dataset "my_dataset"
425
+ # model = dataset.model "my_model"
426
+ #
427
+ # key_name = "projects/a/locations/b/keyRings/c/cryptoKeys/d"
428
+ # encrypt_config = bigquery.encryption kms_key: key_name
429
+ #
430
+ # model.encryption = encrypt_config
431
+ #
432
+ # @!group Attributes
433
+ #
434
+ def encryption= value
435
+ ensure_full_data!
436
+ # We have to create a hash from the gapic object's JSON because that
437
+ # is what Model is expecing.
438
+ json_cmek = JSON.parse value.to_gapi.to_json, symbolize_names: true
439
+ patch_gapi! encryptionConfiguration: json_cmek
440
+ end
441
+
442
+ ##
443
+ # The input feature columns that were used to train this model.
444
+ #
445
+ # @return [Array<StandardSql::Field>]
446
+ #
447
+ # @!group Attributes
448
+ #
449
+ def feature_columns
450
+ ensure_full_data!
451
+ Array(@gapi_json[:featureColumns]).map do |field_gapi_json|
452
+ field_gapi = Google::Apis::BigqueryV2::StandardSqlField.from_json field_gapi_json.to_json
453
+ StandardSql::Field.from_gapi field_gapi
454
+ end
455
+ end
456
+
457
+ ##
458
+ # The label columns that were used to train this model. The output of
459
+ # the model will have a "predicted_" prefix to these columns.
460
+ #
461
+ # @return [Array<StandardSql::Field>]
462
+ #
463
+ # @!group Attributes
464
+ #
465
+ def label_columns
466
+ ensure_full_data!
467
+ Array(@gapi_json[:labelColumns]).map do |field_gapi_json|
468
+ field_gapi = Google::Apis::BigqueryV2::StandardSqlField.from_json field_gapi_json.to_json
469
+ StandardSql::Field.from_gapi field_gapi
470
+ end
471
+ end
472
+
473
+ ##
474
+ # Information for all training runs in increasing order of startTime.
475
+ #
476
+ # @return [Array<Google::Cloud::Bigquery::Model::TrainingRun>]
477
+ #
478
+ # @!group Attributes
479
+ #
480
+ def training_runs
481
+ ensure_full_data!
482
+ Array @gapi_json[:trainingRuns]
483
+ end
484
+
485
+ ##
486
+ # Permanently deletes the model.
487
+ #
488
+ # @return [Boolean] Returns `true` if the model was deleted.
489
+ #
490
+ # @example
491
+ # require "google/cloud/bigquery"
492
+ #
493
+ # bigquery = Google::Cloud::Bigquery.new
494
+ # dataset = bigquery.dataset "my_dataset"
495
+ # model = dataset.model "my_model"
496
+ #
497
+ # model.delete
498
+ #
499
+ # @!group Lifecycle
500
+ #
501
+ def delete
502
+ ensure_service!
503
+ service.delete_model dataset_id, model_id
504
+ # Set flag for #exists?
505
+ @exists = false
506
+ true
507
+ end
508
+
509
+ ##
510
+ # Reloads the model with current data from the BigQuery service.
511
+ #
512
+ # @return [Google::Cloud::Bigquery::Model] Returns the reloaded
513
+ # model.
514
+ #
515
+ # @example Skip retrieving the model from the service, then load it:
516
+ # require "google/cloud/bigquery"
517
+ #
518
+ # bigquery = Google::Cloud::Bigquery.new
519
+ #
520
+ # dataset = bigquery.dataset "my_dataset"
521
+ # model = dataset.model "my_model", skip_lookup: true
522
+ #
523
+ # model.reference? #=> true
524
+ # model.reload!
525
+ # model.resource? #=> true
526
+ #
527
+ # @!group Lifecycle
528
+ #
529
+ def reload!
530
+ ensure_service!
531
+ @gapi_json = service.get_model dataset_id, model_id
532
+ @reference = nil
533
+ @exists = nil
534
+ self
535
+ end
536
+ alias refresh! reload!
537
+
538
+ ##
539
+ # Determines whether the model exists in the BigQuery service. The
540
+ # result is cached locally. To refresh state, set `force` to `true`.
541
+ #
542
+ # @param [Boolean] force Force the latest resource representation to be
543
+ # retrieved from the BigQuery service when `true`. Otherwise the
544
+ # return value of this method will be memoized to reduce the number of
545
+ # API calls made to the BigQuery service. The default is `false`.
546
+ #
547
+ # @return [Boolean] `true` when the model exists in the BigQuery
548
+ # service, `false` otherwise.
549
+ #
550
+ # @example
551
+ # require "google/cloud/bigquery"
552
+ #
553
+ # bigquery = Google::Cloud::Bigquery.new
554
+ #
555
+ # dataset = bigquery.dataset "my_dataset"
556
+ # model = dataset.model "my_model", skip_lookup: true
557
+ # model.exists? #=> true
558
+ #
559
+ def exists? force: false
560
+ return resource_exists? if force
561
+ # If we have a value, return it
562
+ return @exists unless @exists.nil?
563
+ # Always true if we have a gapi_json object
564
+ return true if resource?
565
+ resource_exists?
566
+ end
567
+
568
+ ##
569
+ # Whether the model was created without retrieving the resource
570
+ # representation from the BigQuery service.
571
+ #
572
+ # @return [Boolean] `true` when the model is just a local reference
573
+ # object, `false` otherwise.
574
+ #
575
+ # @example
576
+ # require "google/cloud/bigquery"
577
+ #
578
+ # bigquery = Google::Cloud::Bigquery.new
579
+ #
580
+ # dataset = bigquery.dataset "my_dataset"
581
+ # model = dataset.model "my_model", skip_lookup: true
582
+ #
583
+ # model.reference? #=> true
584
+ # model.reload!
585
+ # model.reference? #=> false
586
+ #
587
+ def reference?
588
+ @gapi_json.nil?
589
+ end
590
+
591
+ ##
592
+ # Whether the model was created with a resource representation from
593
+ # the BigQuery service.
594
+ #
595
+ # @return [Boolean] `true` when the model was created with a resource
596
+ # representation, `false` otherwise.
597
+ #
598
+ # @example
599
+ # require "google/cloud/bigquery"
600
+ #
601
+ # bigquery = Google::Cloud::Bigquery.new
602
+ #
603
+ # dataset = bigquery.dataset "my_dataset"
604
+ # model = dataset.model "my_model", skip_lookup: true
605
+ #
606
+ # model.resource? #=> false
607
+ # model.reload!
608
+ # model.resource? #=> true
609
+ #
610
+ def resource?
611
+ !@gapi_json.nil?
612
+ end
613
+
614
+ ##
615
+ # Whether the model was created with a partial resource representation
616
+ # from the BigQuery service by retrieval through {Dataset#models}.
617
+ # See [Models: list
618
+ # response](https://cloud.google.com/bigquery/docs/reference/rest/v2/models/list#response)
619
+ # for the contents of the partial representation. Accessing any
620
+ # attribute outside of the partial representation will result in loading
621
+ # the full representation.
622
+ #
623
+ # @return [Boolean] `true` when the model was created with a partial
624
+ # resource representation, `false` otherwise.
625
+ #
626
+ # @example
627
+ # require "google/cloud/bigquery"
628
+ #
629
+ # bigquery = Google::Cloud::Bigquery.new
630
+ #
631
+ # dataset = bigquery.dataset "my_dataset"
632
+ # model = dataset.models.first
633
+ #
634
+ # model.resource_partial? #=> true
635
+ # model.description # Loads the full resource.
636
+ # model.resource_partial? #=> false
637
+ #
638
+ def resource_partial?
639
+ resource? && !resource_full?
640
+ end
641
+
642
+ ##
643
+ # Whether the model was created with a full resource representation
644
+ # from the BigQuery service.
645
+ #
646
+ # @return [Boolean] `true` when the model was created with a full
647
+ # resource representation, `false` otherwise.
648
+ #
649
+ # @example
650
+ # require "google/cloud/bigquery"
651
+ #
652
+ # bigquery = Google::Cloud::Bigquery.new
653
+ #
654
+ # dataset = bigquery.dataset "my_dataset"
655
+ # model = dataset.model "my_model"
656
+ #
657
+ # model.resource_full? #=> true
658
+ #
659
+ def resource_full?
660
+ resource? && @gapi_json.key?(:friendlyName)
661
+ end
662
+
663
+ ##
664
+ # @private New Model from a Google API Client object.
665
+ def self.from_gapi_json gapi_json, service
666
+ new.tap do |m|
667
+ m.instance_variable_set :@gapi_json, gapi_json
668
+ m.instance_variable_set :@service, service
669
+ end
670
+ end
671
+
672
+ ##
673
+ # @private New lazy Model object without making an HTTP request, for use with the skip_lookup option.
674
+ def self.new_reference project_id, dataset_id, model_id, service
675
+ raise ArgumentError, "project_id is required" unless project_id
676
+ raise ArgumentError, "dataset_id is required" unless dataset_id
677
+ raise ArgumentError, "model_id is required" unless model_id
678
+ raise ArgumentError, "service is required" unless service
679
+
680
+ new.tap do |m|
681
+ reference_gapi_json = Google::Apis::BigqueryV2::ModelReference.new(
682
+ project_id: project_id,
683
+ dataset_id: dataset_id,
684
+ model_id: model_id
685
+ )
686
+ m.instance_variable_set :@reference, reference_gapi_json
687
+ m.instance_variable_set :@service, service
688
+ end
689
+ end
690
+
691
+ protected
692
+
693
+ ##
694
+ # Raise an error unless an active service is available.
695
+ def ensure_service!
696
+ raise "Must have active connection" unless service
697
+ end
698
+
699
+ ##
700
+ # Ensures the Google::Apis::BigqueryV2::Model object has been loaded
701
+ # from the service.
702
+ def ensure_gapi_json!
703
+ ensure_service!
704
+ return unless reference?
705
+ reload!
706
+ end
707
+
708
+ ##
709
+ # Fetch gapi_json and memoize whether resource exists.
710
+ def resource_exists?
711
+ reload!
712
+ @exists = true
713
+ rescue Google::Cloud::NotFoundError
714
+ @exists = false
715
+ end
716
+
717
+ def patch_gapi! **changes
718
+ return if changes.empty?
719
+ ensure_service!
720
+ patch_gapi = Google::Apis::BigqueryV2::Model.from_json changes.to_json
721
+ patch_gapi.model_reference = model_ref
722
+ @gapi_json = service.patch_model \
723
+ dataset_id, model_id, patch_gapi, etag
724
+ @reference = nil
725
+
726
+ # TODO: restore original impl after acceptance test indicates that
727
+ # service etag bug is fixed
728
+ reload!
729
+ end
730
+
731
+ ##
732
+ # Load the complete representation of the model if it has been
733
+ # only partially loaded by a request to the API list method.
734
+ def ensure_full_data!
735
+ reload! unless resource_full?
736
+ end
737
+ end
738
+ end
739
+ end
740
+ end