google-cloud-bigquery 0.29.0 → 0.30.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 58e73b43f4053457d2df061703e3314483552dbb
4
- data.tar.gz: 927a49cb45ff1a1c2aac5fa319e19dc0b422af23
2
+ SHA256:
3
+ metadata.gz: 8c5eccec9f2f10fd5b5637a91516d68bee4f8b7f2e7e8e58a6b213afe89e56fe
4
+ data.tar.gz: 55d8b9b98cd3e52bb7c6111feaa9811487c61a4b2868126c54af7f9dec5fde1b
5
5
  SHA512:
6
- metadata.gz: 8d86f37859a1a6cf2b682afd8b4e3f77b178fb8333e47606673e02e0a5e6ba76e61c6ee3c9bfbd5bd8d4763eff03f9c54bc067c10f39883772a6c730c0d8b443
7
- data.tar.gz: d9d5afd3aac9c23e523909d78b7ae5fc886ce783e5b3cad0068aff21a815841a564e9baf6f35b2235adf0ed743df55d41c33b570f9b99a5d5a96ea50768882d0
6
+ metadata.gz: 6377e7a4cef9081723669ae08913786a1cdb37d65b0ae922dfc0a930e664eec451f95802e3f95f96eefcf24a5bf2eff23b00102bdd1f449a076018b7fc4d61cc
7
+ data.tar.gz: 9a4e917438c795ba7baa5692c5c6b70de0593b047e575f6113f112221d5c9925348e17ed6564d9361a872d6ca9918ac12df421a217e1d6e1096e98649829e447
data/README.md CHANGED
@@ -24,8 +24,8 @@ Instructions and configuration options are covered in the [Authentication Guide]
24
24
  require "google/cloud/bigquery"
25
25
 
26
26
  bigquery = Google::Cloud::Bigquery.new(
27
- project: "my-todo-project",
28
- keyfile: "/path/to/keyfile.json"
27
+ project_id: "my-todo-project",
28
+ credentials: "/path/to/keyfile.json"
29
29
  )
30
30
 
31
31
  # Create a new table to archive todos
@@ -13,9 +13,9 @@
13
13
  # limitations under the License.
14
14
 
15
15
  ##
16
- # This file is here to be autorequired by bundler, so that the .bigquery and
17
- # #bigquery methods can be available, but the library and all dependencies won't
18
- # be loaded until required and used.
16
+ # This file is here to be autorequired by bundler, so that the
17
+ # Google::Cloud.bigquery and Google::Cloud#bigquery methods can be available,
18
+ # but the library and all dependencies won't be loaded until required and used.
19
19
 
20
20
 
21
21
  gem "google-cloud-core"
@@ -75,10 +75,11 @@ module Google
75
75
  # For more information on connecting to Google Cloud see the [Authentication
76
76
  # Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
77
77
  #
78
- # @param [String] project Identifier for a BigQuery project. If not present,
79
- # the default project for the credentials is used.
80
- # @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
81
- # file path the file must be readable.
78
+ # @param [String] project_id Identifier for a BigQuery project. If not
79
+ # present, the default project for the credentials is used.
80
+ # @param [String, Hash, Google::Auth::Credentials] credentials The path to
81
+ # the keyfile as a String, the contents of the keyfile as a Hash, or a
82
+ # Google::Auth::Credentials object. (See {Bigquery::Credentials})
82
83
  # @param [String, Array<String>] scope The OAuth 2.0 scopes controlling the
83
84
  # set of resources and operations that the connection can access. See
84
85
  # [Using OAuth 2.0 to Access Google
@@ -100,10 +101,11 @@ module Google
100
101
  # dataset = bigquery.dataset "my_dataset"
101
102
  # table = dataset.table "my_table"
102
103
  #
103
- def self.bigquery project = nil, keyfile = nil, scope: nil, retries: nil,
104
- timeout: nil
104
+ def self.bigquery project_id = nil, credentials = nil, scope: nil,
105
+ retries: nil, timeout: nil
105
106
  require "google/cloud/bigquery"
106
- Google::Cloud::Bigquery.new project: project, keyfile: keyfile,
107
+ Google::Cloud::Bigquery.new project_id: project_id,
108
+ credentials: credentials,
107
109
  scope: scope, retries: retries,
108
110
  timeout: timeout
109
111
  end
@@ -347,6 +347,45 @@ module Google
347
347
  # table.insert rows
348
348
  # ```
349
349
  #
350
+ # To avoid making RPCs (network requests) to retrieve the dataset and table
351
+ # resources when streaming records, pass the `skip_lookup` option. This
352
+ # creates local objects without verifying that the resources exist on the
353
+ # BigQuery service.
354
+ #
355
+ # ```ruby
356
+ # require "google/cloud/bigquery"
357
+ #
358
+ # bigquery = Google::Cloud::Bigquery.new
359
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
360
+ # table = dataset.table "people", skip_lookup: true
361
+ #
362
+ # rows = [
363
+ # {
364
+ # "first_name" => "Anna",
365
+ # "cities_lived" => [
366
+ # {
367
+ # "place" => "Stockholm",
368
+ # "number_of_years" => 2
369
+ # }
370
+ # ]
371
+ # },
372
+ # {
373
+ # "first_name" => "Bob",
374
+ # "cities_lived" => [
375
+ # {
376
+ # "place" => "Seattle",
377
+ # "number_of_years" => 5
378
+ # },
379
+ # {
380
+ # "place" => "Austin",
381
+ # "number_of_years" => 6
382
+ # }
383
+ # ]
384
+ # }
385
+ # ]
386
+ # table.insert rows
387
+ # ```
388
+ #
350
389
  # There are some trade-offs involved with streaming, so be sure to read the
351
390
  # discussion of data consistency in [Streaming Data Into
352
391
  # BigQuery](https://cloud.google.com/bigquery/streaming-data-into-bigquery).
@@ -455,10 +494,11 @@ module Google
455
494
  # [Authentication
456
495
  # Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
457
496
  #
458
- # @param [String] project Identifier for a BigQuery project. If not
497
+ # @param [String] project_id Identifier for a BigQuery project. If not
459
498
  # present, the default project for the credentials is used.
460
- # @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
461
- # file path the file must be readable.
499
+ # @param [String, Hash, Google::Auth::Credentials] credentials The path to
500
+ # the keyfile as a String, the contents of the keyfile as a Hash, or a
501
+ # Google::Auth::Credentials object. (See {Bigquery::Credentials})
462
502
  # @param [String, Array<String>] scope The OAuth 2.0 scopes controlling
463
503
  # the set of resources and operations that the connection can access.
464
504
  # See # [Using OAuth 2.0 to Access Google #
@@ -470,6 +510,9 @@ module Google
470
510
  # @param [Integer] retries Number of times to retry requests on server
471
511
  # error. The default value is `5`. Optional.
472
512
  # @param [Integer] timeout Default timeout to use in requests. Optional.
513
+ # @param [String] project Alias for the `project_id` argument. Deprecated.
514
+ # @param [String] keyfile Alias for the `credentials` argument.
515
+ # Deprecated.
473
516
  #
474
517
  # @return [Google::Cloud::Bigquery::Project]
475
518
  #
@@ -480,23 +523,20 @@ module Google
480
523
  # dataset = bigquery.dataset "my_dataset"
481
524
  # table = dataset.table "my_table"
482
525
  #
483
- def self.new project: nil, keyfile: nil, scope: nil, retries: nil,
484
- timeout: nil
485
- project ||= Google::Cloud::Bigquery::Project.default_project
486
- project = project.to_s # Always cast to a string
487
- fail ArgumentError, "project is missing" if project.empty?
526
+ def self.new project_id: nil, credentials: nil, scope: nil, retries: nil,
527
+ timeout: nil, project: nil, keyfile: nil
528
+ project_id ||= (project || Bigquery::Project.default_project_id)
529
+ project_id = project_id.to_s # Always cast to a string
530
+ fail ArgumentError, "project_id is missing" if project_id.empty?
488
531
 
489
- if keyfile.nil?
490
- credentials = Google::Cloud::Bigquery::Credentials.default(
491
- scope: scope)
492
- else
493
- credentials = Google::Cloud::Bigquery::Credentials.new(
494
- keyfile, scope: scope)
532
+ credentials ||= (keyfile || Bigquery::Credentials.default(scope: scope))
533
+ unless credentials.is_a? Google::Auth::Credentials
534
+ credentials = Bigquery::Credentials.new credentials, scope: scope
495
535
  end
496
536
 
497
- Google::Cloud::Bigquery::Project.new(
498
- Google::Cloud::Bigquery::Service.new(
499
- project, credentials, retries: retries, timeout: timeout))
537
+ Bigquery::Project.new(
538
+ Bigquery::Service.new(
539
+ project_id, credentials, retries: retries, timeout: timeout))
500
540
  end
501
541
  end
502
542
  end
@@ -13,18 +13,44 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- require "google/cloud/credentials"
16
+ require "googleauth"
17
17
 
18
18
  module Google
19
19
  module Cloud
20
20
  module Bigquery
21
21
  ##
22
- # @private Represents the Oauth2 signing logic for Bigquery.
23
- class Credentials < Google::Cloud::Credentials
22
+ # # Credentials
23
+ #
24
+ # Represents the authentication and authorization used to connect to the
25
+ # BigQuery API.
26
+ #
27
+ # @example
28
+ # require "google/cloud/bigquery"
29
+ #
30
+ # keyfile = "/path/to/keyfile.json"
31
+ # creds = Google::Cloud::Bigquery::Credentials.new keyfile
32
+ #
33
+ # bigquery = Google::Cloud::Bigquery.new(
34
+ # project_id: "my-project",
35
+ # credentials: creds
36
+ # )
37
+ #
38
+ # bigquery.project_id #=> "my-project"
39
+ #
40
+ class Credentials < Google::Auth::Credentials
24
41
  SCOPE = ["https://www.googleapis.com/auth/bigquery"]
25
- PATH_ENV_VARS = %w(BIGQUERY_KEYFILE GOOGLE_CLOUD_KEYFILE GCLOUD_KEYFILE)
26
- JSON_ENV_VARS = %w(BIGQUERY_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON
42
+ PATH_ENV_VARS = %w(BIGQUERY_CREDENTIALS
43
+ GOOGLE_CLOUD_CREDENTIALS
44
+ BIGQUERY_KEYFILE
45
+ GOOGLE_CLOUD_KEYFILE
46
+ GCLOUD_KEYFILE)
47
+ JSON_ENV_VARS = %w(BIGQUERY_CREDENTIALS_JSON
48
+ GOOGLE_CLOUD_CREDENTIALS_JSON
49
+ BIGQUERY_KEYFILE_JSON
50
+ GOOGLE_CLOUD_KEYFILE_JSON
27
51
  GCLOUD_KEYFILE_JSON)
52
+ DEFAULT_PATHS = \
53
+ ["~/.config/gcloud/application_default_credentials.json"]
28
54
  end
29
55
  end
30
56
  end
@@ -49,14 +49,14 @@ module Google
49
49
  attr_accessor :table_gapi
50
50
 
51
51
  ##
52
- # @private The Google API Client object.
53
- attr_accessor :gapi
52
+ # @private The Google API Client object in JSON Hash.
53
+ attr_accessor :gapi_json
54
54
 
55
55
  # @private
56
56
  def initialize arr = []
57
57
  @service = nil
58
58
  @table_gapi = nil
59
- @gapi = nil
59
+ @gapi_json = nil
60
60
  super arr
61
61
  end
62
62
 
@@ -66,7 +66,7 @@ module Google
66
66
  # @return [String] The resource type.
67
67
  #
68
68
  def kind
69
- @gapi.kind
69
+ @gapi_json[:kind]
70
70
  end
71
71
 
72
72
  ##
@@ -75,7 +75,7 @@ module Google
75
75
  # @return [String] The ETag hash.
76
76
  #
77
77
  def etag
78
- @gapi.etag
78
+ @gapi_json[:etag]
79
79
  end
80
80
 
81
81
  ##
@@ -85,7 +85,7 @@ module Google
85
85
  # @return [String] The pagination token.
86
86
  #
87
87
  def token
88
- @gapi.page_token
88
+ @gapi_json[:pageToken]
89
89
  end
90
90
 
91
91
  ##
@@ -107,7 +107,7 @@ module Google
107
107
  # end
108
108
  #
109
109
  def total
110
- Integer @gapi.total_rows
110
+ Integer @gapi_json[:totalRows]
111
111
  rescue
112
112
  nil
113
113
  end
@@ -224,11 +224,11 @@ module Google
224
224
  def next
225
225
  return nil unless next?
226
226
  ensure_service!
227
- data_gapi = service.list_tabledata \
227
+ data_json = service.list_tabledata \
228
228
  @table_gapi.table_reference.dataset_id,
229
229
  @table_gapi.table_reference.table_id,
230
230
  token: token
231
- self.class.from_gapi data_gapi, @table_gapi, @service
231
+ self.class.from_gapi_json data_json, @table_gapi, @service
232
232
  end
233
233
 
234
234
  ##
@@ -302,13 +302,13 @@ module Google
302
302
 
303
303
  ##
304
304
  # @private New Data from a response object.
305
- def self.from_gapi gapi, table_gapi, service
306
- formatted_rows = Convert.format_rows(gapi.rows,
305
+ def self.from_gapi_json gapi_json, table_gapi, service
306
+ formatted_rows = Convert.format_rows(gapi_json[:rows],
307
307
  table_gapi.schema.fields)
308
308
 
309
309
  data = new formatted_rows
310
310
  data.table_gapi = table_gapi
311
- data.gapi = gapi
311
+ data.gapi_json = gapi_json
312
312
  data.service = service
313
313
  data
314
314
  end
@@ -51,11 +51,16 @@ module Google
51
51
  # @private The Google API Client object.
52
52
  attr_accessor :gapi
53
53
 
54
+ ##
55
+ # @private A Google API Client Dataset Reference object.
56
+ attr_reader :reference
57
+
54
58
  ##
55
59
  # @private Create an empty Dataset object.
56
60
  def initialize
57
61
  @service = nil
58
- @gapi = {}
62
+ @gapi = nil
63
+ @reference = nil
59
64
  end
60
65
 
61
66
  ##
@@ -67,6 +72,7 @@ module Google
67
72
  # @!group Attributes
68
73
  #
69
74
  def dataset_id
75
+ return reference.dataset_id if reference?
70
76
  @gapi.dataset_reference.dataset_id
71
77
  end
72
78
 
@@ -78,6 +84,7 @@ module Google
78
84
  # @!group Attributes
79
85
  #
80
86
  def project_id
87
+ return reference.project_id if reference?
81
88
  @gapi.dataset_reference.project_id
82
89
  end
83
90
 
@@ -86,7 +93,7 @@ module Google
86
93
  # The gapi fragment containing the Project ID and Dataset ID as a
87
94
  # camel-cased hash.
88
95
  def dataset_ref
89
- dataset_ref = @gapi.dataset_reference
96
+ dataset_ref = reference? ? reference : @gapi.dataset_reference
90
97
  dataset_ref = dataset_ref.to_h if dataset_ref.respond_to? :to_h
91
98
  dataset_ref
92
99
  end
@@ -94,22 +101,30 @@ module Google
94
101
  ##
95
102
  # A descriptive name for the dataset.
96
103
  #
97
- # @return [String] The friendly name.
104
+ # @return [String, nil] The friendly name, or `nil` if the object is
105
+ # a reference (see {#reference?}).
98
106
  #
99
107
  # @!group Attributes
100
108
  #
101
109
  def name
110
+ return nil if reference?
102
111
  @gapi.friendly_name
103
112
  end
104
113
 
105
114
  ##
106
115
  # Updates the descriptive name for the dataset.
107
116
  #
108
- # @param [String] new_name The new friendly name.
117
+ # If the dataset is not a full resource representation (see
118
+ # {#resource_full?}), the full representation will be retrieved before
119
+ # the update to comply with ETag-based optimistic concurrency control.
120
+ #
121
+ # @param [String] new_name The new friendly name, or `nil` if the object
122
+ # is a reference (see {#reference?}).
109
123
  #
110
124
  # @!group Attributes
111
125
  #
112
126
  def name= new_name
127
+ reload! unless resource_full?
113
128
  @gapi.update! friendly_name: new_name
114
129
  patch_gapi! :friendly_name
115
130
  end
@@ -117,11 +132,13 @@ module Google
117
132
  ##
118
133
  # The ETag hash of the dataset.
119
134
  #
120
- # @return [String] The ETag hash.
135
+ # @return [String, nil] The ETag hash, or `nil` if the object is a
136
+ # reference (see {#reference?}).
121
137
  #
122
138
  # @!group Attributes
123
139
  #
124
140
  def etag
141
+ return nil if reference?
125
142
  ensure_full_data!
126
143
  @gapi.etag
127
144
  end
@@ -129,11 +146,13 @@ module Google
129
146
  ##
130
147
  # A URL that can be used to access the dataset using the REST API.
131
148
  #
132
- # @return [String] A REST URL for the resource.
149
+ # @return [String, nil] A REST URL for the resource, or `nil` if the
150
+ # object is a reference (see {#reference?}).
133
151
  #
134
152
  # @!group Attributes
135
153
  #
136
154
  def api_url
155
+ return nil if reference?
137
156
  ensure_full_data!
138
157
  @gapi.self_link
139
158
  end
@@ -141,11 +160,13 @@ module Google
141
160
  ##
142
161
  # A user-friendly description of the dataset.
143
162
  #
144
- # @return [String] The description.
163
+ # @return [String, nil] The description, or `nil` if the object is a
164
+ # reference (see {#reference?}).
145
165
  #
146
166
  # @!group Attributes
147
167
  #
148
168
  def description
169
+ return nil if reference?
149
170
  ensure_full_data!
150
171
  @gapi.description
151
172
  end
@@ -153,11 +174,16 @@ module Google
153
174
  ##
154
175
  # Updates the user-friendly description of the dataset.
155
176
  #
177
+ # If the dataset is not a full resource representation (see
178
+ # {#resource_full?}), the full representation will be retrieved before
179
+ # the update to comply with ETag-based optimistic concurrency control.
180
+ #
156
181
  # @param [String] new_description The new description for the dataset.
157
182
  #
158
183
  # @!group Attributes
159
184
  #
160
185
  def description= new_description
186
+ reload! unless resource_full?
161
187
  @gapi.update! description: new_description
162
188
  patch_gapi! :description
163
189
  end
@@ -165,11 +191,14 @@ module Google
165
191
  ##
166
192
  # The default lifetime of all tables in the dataset, in milliseconds.
167
193
  #
168
- # @return [Integer] The default table expiration in milliseconds.
194
+ # @return [Integer, nil] The default table expiration in milliseconds,
195
+ # or `nil` if not present or the object is a reference (see
196
+ # {#reference?}).
169
197
  #
170
198
  # @!group Attributes
171
199
  #
172
200
  def default_expiration
201
+ return nil if reference?
173
202
  ensure_full_data!
174
203
  begin
175
204
  Integer @gapi.default_table_expiration_ms
@@ -182,12 +211,17 @@ module Google
182
211
  # Updates the default lifetime of all tables in the dataset, in
183
212
  # milliseconds.
184
213
  #
214
+ # If the dataset is not a full resource representation (see
215
+ # {#resource_full?}), the full representation will be retrieved before
216
+ # the update to comply with ETag-based optimistic concurrency control.
217
+ #
185
218
  # @param [Integer] new_default_expiration The new default table
186
219
  # expiration in milliseconds.
187
220
  #
188
221
  # @!group Attributes
189
222
  #
190
223
  def default_expiration= new_default_expiration
224
+ reload! unless resource_full?
191
225
  @gapi.update! default_table_expiration_ms: new_default_expiration
192
226
  patch_gapi! :default_table_expiration_ms
193
227
  end
@@ -195,11 +229,13 @@ module Google
195
229
  ##
196
230
  # The time when this dataset was created.
197
231
  #
198
- # @return [Time, nil] The creation time.
232
+ # @return [Time, nil] The creation time, or `nil` if not present or the
233
+ # object is a reference (see {#reference?}).
199
234
  #
200
235
  # @!group Attributes
201
236
  #
202
237
  def created_at
238
+ return nil if reference?
203
239
  ensure_full_data!
204
240
  begin
205
241
  ::Time.at(Integer(@gapi.creation_time) / 1000.0)
@@ -211,11 +247,13 @@ module Google
211
247
  ##
212
248
  # The date when this dataset or any of its tables was last modified.
213
249
  #
214
- # @return [Time, nil] The last modified time.
250
+ # @return [Time, nil] The last modified time, or `nil` if not present or
251
+ # the object is a reference (see {#reference?}).
215
252
  #
216
253
  # @!group Attributes
217
254
  #
218
255
  def modified_at
256
+ return nil if reference?
219
257
  ensure_full_data!
220
258
  begin
221
259
  ::Time.at(Integer(@gapi.last_modified_time) / 1000.0)
@@ -228,11 +266,13 @@ module Google
228
266
  # The geographic location where the dataset should reside. Possible
229
267
  # values include `EU` and `US`. The default value is `US`.
230
268
  #
231
- # @return [String] The location code.
269
+ # @return [String, nil] The location code, or `nil` if the object is a
270
+ # reference (see {#reference?}).
232
271
  #
233
272
  # @!group Attributes
234
273
  #
235
274
  def location
275
+ return nil if reference?
236
276
  ensure_full_data!
237
277
  @gapi.location
238
278
  end
@@ -245,7 +285,8 @@ module Google
245
285
  # The returned hash is frozen and changes are not allowed. Use
246
286
  # {#labels=} to replace the entire hash.
247
287
  #
248
- # @return [Hash<String, String>] A hash containing key/value pairs.
288
+ # @return [Hash<String, String>, nil] A hash containing key/value pairs,
289
+ # or `nil` if the object is a reference (see {#reference?}).
249
290
  #
250
291
  # @example
251
292
  # require "google/cloud/bigquery"
@@ -259,6 +300,7 @@ module Google
259
300
  # @!group Attributes
260
301
  #
261
302
  def labels
303
+ return nil if reference?
262
304
  m = @gapi.labels
263
305
  m = m.to_h if m.respond_to? :to_h
264
306
  m.dup.freeze
@@ -269,6 +311,10 @@ module Google
269
311
  # Labels are used to organize and group datasets. See [Using
270
312
  # Labels](https://cloud.google.com/bigquery/docs/labels).
271
313
  #
314
+ # If the dataset is not a full resource representation (see
315
+ # {#resource_full?}), the full representation will be retrieved before
316
+ # the update to comply with ETag-based optimistic concurrency control.
317
+ #
272
318
  # @param [Hash<String, String>] labels A hash containing key/value
273
319
  # pairs.
274
320
  #
@@ -290,6 +336,7 @@ module Google
290
336
  # @!group Attributes
291
337
  #
292
338
  def labels= labels
339
+ reload! unless resource_full?
293
340
  @gapi.labels = labels
294
341
  patch_gapi! :labels
295
342
  end
@@ -299,6 +346,10 @@ module Google
299
346
  # when passing a block, see {Dataset::Access} for all the methods
300
347
  # available.
301
348
  #
349
+ # If the dataset is not a full resource representation (see
350
+ # {#resource_full?}), the full representation will be retrieved before
351
+ # the update to comply with ETag-based optimistic concurrency control.
352
+ #
302
353
  # @see https://cloud.google.com/bigquery/access-control BigQuery Access
303
354
  # Control
304
355
  #
@@ -332,6 +383,7 @@ module Google
332
383
  #
333
384
  def access
334
385
  ensure_full_data!
386
+ reload! unless resource_full?
335
387
  access_builder = Access.from_gapi @gapi
336
388
  if block_given?
337
389
  yield access_builder
@@ -455,7 +507,14 @@ module Google
455
507
  end
456
508
 
457
509
  ##
458
- # Creates a new view table from the given query.
510
+ # Creates a new [view](https://cloud.google.com/bigquery/docs/views)
511
+ # table, which is a virtual table defined by the given SQL query.
512
+ #
513
+ # BigQuery's views are logical views, not materialized views, which
514
+ # means that the query that defines the view is re-executed every time
515
+ # the view is queried. Queries are billed according to the total amount
516
+ # of data in all table fields referenced directly or indirectly by the
517
+ # top-level query. (See {Table#view?} and {Table#query}.)
459
518
  #
460
519
  # @param [String] table_id The ID of the view table. The ID must contain
461
520
  # only letters (a-z, A-Z), numbers (0-9), or underscores (_). The
@@ -480,7 +539,7 @@ module Google
480
539
  # containing the same code. See [User-Defined
481
540
  # Functions](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions).
482
541
  #
483
- # @return [Google::Cloud::Bigquery::View] A new view object.
542
+ # @return [Google::Cloud::Bigquery::Table] A new table object.
484
543
  #
485
544
  # @example
486
545
  # require "google/cloud/bigquery"
@@ -528,10 +587,13 @@ module Google
528
587
  # Retrieves an existing table by ID.
529
588
  #
530
589
  # @param [String] table_id The ID of a table.
590
+ # @param [Boolean] skip_lookup Optionally create just a local reference
591
+ # object without verifying that the resource exists on the BigQuery
592
+ # service. Calls made on this object will raise errors if the resource
593
+ # does not exist. Default is `false`. Optional.
531
594
  #
532
- # @return [Google::Cloud::Bigquery::Table,
533
- # Google::Cloud::Bigquery::View, nil] Returns `nil` if the table does
534
- # not exist
595
+ # @return [Google::Cloud::Bigquery::Table, nil] Returns `nil` if the
596
+ # table does not exist.
535
597
  #
536
598
  # @example
537
599
  # require "google/cloud/bigquery"
@@ -542,10 +604,22 @@ module Google
542
604
  # table = dataset.table "my_table"
543
605
  # puts table.name
544
606
  #
607
+ # @example Avoid retrieving the table resource with `skip_lookup`:
608
+ # require "google/cloud/bigquery"
609
+ #
610
+ # bigquery = Google::Cloud::Bigquery.new
611
+ #
612
+ # dataset = bigquery.dataset "my_dataset"
613
+ #
614
+ # table = dataset.table "my_table", skip_lookup: true
615
+ #
545
616
  # @!group Table
546
617
  #
547
- def table table_id
618
+ def table table_id, skip_lookup: nil
548
619
  ensure_service!
620
+ if skip_lookup
621
+ return Table.new_reference project_id, dataset_id, table_id, service
622
+ end
549
623
  gapi = service.get_table dataset_id, table_id
550
624
  Table.from_gapi gapi, service
551
625
  rescue Google::Cloud::NotFoundError
@@ -559,9 +633,8 @@ module Google
559
633
  # part of the larger set of results to view.
560
634
  # @param [Integer] max Maximum number of tables to return.
561
635
  #
562
- # @return [Array<Google::Cloud::Bigquery::Table>,
563
- # Array<Google::Cloud::Bigquery::View>] An array of tables and/or
564
- # views(See {Google::Cloud::Bigquery::Table::List})
636
+ # @return [Array<Google::Cloud::Bigquery::Table>] An array of tables
637
+ # (See {Google::Cloud::Bigquery::Table::List})
565
638
  #
566
639
  # @example
567
640
  # require "google/cloud/bigquery"
@@ -1507,6 +1580,146 @@ module Google
1507
1580
  true
1508
1581
  end
1509
1582
 
1583
+ ##
1584
+ # Reloads the dataset with current data from the BigQuery service.
1585
+ #
1586
+ # @return [Google::Cloud::Bigquery::Dataset] Returns the reloaded
1587
+ # dataset.
1588
+ #
1589
+ # @example Skip retrieving the dataset from the service, then load it:
1590
+ # require "google/cloud/bigquery"
1591
+ #
1592
+ # bigquery = Google::Cloud::Bigquery.new
1593
+ #
1594
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
1595
+ # dataset.reload!
1596
+ #
1597
+ def reload!
1598
+ ensure_service!
1599
+ reloaded_gapi = service.get_dataset dataset_id
1600
+ @reference = nil
1601
+ @gapi = reloaded_gapi
1602
+ self
1603
+ end
1604
+ alias_method :refresh!, :reload!
1605
+
1606
+ ##
1607
+ # Determines whether the dataset exists in the BigQuery service. The
1608
+ # result is cached locally.
1609
+ #
1610
+ # @return [Boolean] `true` when the dataset exists in the BigQuery
1611
+ # service, `false` otherwise.
1612
+ #
1613
+ # @example
1614
+ # require "google/cloud/bigquery"
1615
+ #
1616
+ # bigquery = Google::Cloud::Bigquery.new
1617
+ #
1618
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
1619
+ # dataset.exists? # true
1620
+ #
1621
+ def exists?
1622
+ # Always true if we have a gapi object
1623
+ return true unless reference?
1624
+ # If we have a value, return it
1625
+ return @exists unless @exists.nil?
1626
+ ensure_gapi!
1627
+ @exists = true
1628
+ rescue Google::Cloud::NotFoundError
1629
+ @exists = false
1630
+ end
1631
+
1632
+ ##
1633
+ # Whether the dataset was created without retrieving the resource
1634
+ # representation from the BigQuery service.
1635
+ #
1636
+ # @return [Boolean] `true` when the dataset is just a local reference
1637
+ # object, `false` otherwise.
1638
+ #
1639
+ # @example
1640
+ # require "google/cloud/bigquery"
1641
+ #
1642
+ # bigquery = Google::Cloud::Bigquery.new
1643
+ #
1644
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
1645
+ #
1646
+ # dataset.reference? # true
1647
+ # dataset.reload!
1648
+ # dataset.reference? # false
1649
+ #
1650
+ def reference?
1651
+ @gapi.nil?
1652
+ end
1653
+
1654
+ ##
1655
+ # Whether the dataset was created with a resource representation from
1656
+ # the BigQuery service.
1657
+ #
1658
+ # @return [Boolean] `true` when the dataset was created with a resource
1659
+ # representation, `false` otherwise.
1660
+ #
1661
+ # @example
1662
+ # require "google/cloud/bigquery"
1663
+ #
1664
+ # bigquery = Google::Cloud::Bigquery.new
1665
+ #
1666
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
1667
+ #
1668
+ # dataset.resource? # false
1669
+ # dataset.reload!
1670
+ # dataset.resource? # true
1671
+ #
1672
+ def resource?
1673
+ !@gapi.nil?
1674
+ end
1675
+
1676
+ ##
1677
+ # Whether the dataset was created with a partial resource representation
1678
+ # from the BigQuery service by retrieval through {Project#datasets}.
1679
+ # See [Datasets: list
1680
+ # response](https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets/list#response)
1681
+ # for the contents of the partial representation. Accessing any
1682
+ # attribute outside of the partial representation will result in loading
1683
+ # the full representation.
1684
+ #
1685
+ # @return [Boolean] `true` when the dataset was created with a partial
1686
+ # resource representation, `false` otherwise.
1687
+ #
1688
+ # @example
1689
+ # require "google/cloud/bigquery"
1690
+ #
1691
+ # bigquery = Google::Cloud::Bigquery.new
1692
+ #
1693
+ # dataset = bigquery.datasets.first
1694
+ #
1695
+ # dataset.resource_partial? # true
1696
+ # dataset.description # Loads the full resource.
1697
+ # dataset.resource_partial? # false
1698
+ #
1699
+ def resource_partial?
1700
+ @gapi.is_a? Google::Apis::BigqueryV2::DatasetList::Dataset
1701
+ end
1702
+
1703
+ ##
1704
+ # Whether the dataset was created with a full resource representation
1705
+ # from the BigQuery service.
1706
+ #
1707
+ # @return [Boolean] `true` when the dataset was created with a full
1708
+ # resource representation, `false` otherwise.
1709
+ #
1710
+ # @example
1711
+ # require "google/cloud/bigquery"
1712
+ #
1713
+ # bigquery = Google::Cloud::Bigquery.new
1714
+ #
1715
+ # dataset = bigquery.dataset "my_dataset"
1716
+ #
1717
+ # dataset.resource_full? # true
1718
+ #
1719
+ def resource_full?
1720
+ @gapi.is_a? Google::Apis::BigqueryV2::Dataset
1721
+ end
1722
+
1510
1723
  ##
1511
1724
  # @private New Dataset from a Google API Client object.
1512
1725
  def self.from_gapi gapi, conn
@@ -1516,6 +1729,20 @@ module Google
1516
1729
  end
1517
1730
  end
1518
1731
 
1732
+ ##
1733
+ # @private New lazy Dataset object without making an HTTP request.
1734
+ def self.new_reference project_id, dataset_id, service
1735
+ # TODO: raise if dataset_id is nil?
1736
+ new.tap do |b|
1737
+ reference_gapi = Google::Apis::BigqueryV2::DatasetReference.new(
1738
+ project_id: project_id,
1739
+ dataset_id: dataset_id
1740
+ )
1741
+ b.service = service
1742
+ b.instance_variable_set :@reference, reference_gapi
1743
+ end
1744
+ end
1745
+
1519
1746
  ##
1520
1747
  # Inserts data into the given table for near-immediate querying, without
1521
1748
  # the need to complete a load operation before the data can appear in
@@ -1552,6 +1779,19 @@ module Google
1552
1779
  # ]
1553
1780
  # dataset.insert "my_table", rows
1554
1781
  #
1782
+ # @example Avoid retrieving the dataset with `skip_lookup`:
1783
+ # require "google/cloud/bigquery"
1784
+ #
1785
+ # bigquery = Google::Cloud::Bigquery.new
1786
+ #
1787
+ # dataset = bigquery.dataset "my_dataset", skip_lookup: true
1788
+ #
1789
+ # rows = [
1790
+ # { "first_name" => "Alice", "age" => 21 },
1791
+ # { "first_name" => "Bob", "age" => 22 }
1792
+ # ]
1793
+ # dataset.insert "my_table", rows
1794
+ #
1555
1795
  # @example Using `autocreate` to create a new table if none exists.
1556
1796
  # require "google/cloud/bigquery"
1557
1797
  #
@@ -1598,7 +1838,7 @@ module Google
1598
1838
  end
1599
1839
 
1600
1840
  ##
1601
- # Create an asynchonous inserter object used to insert rows in batches.
1841
+ # Create an asynchronous inserter object used to insert rows in batches.
1602
1842
  #
1603
1843
  # @param [String] table_id The ID of the table to insert rows into.
1604
1844
  # @param [Boolean] skip_invalid Insert all valid rows of a request, even
@@ -1617,8 +1857,8 @@ module Google
1617
1857
  # @attr_reader [Numeric] threads The number of threads used to insert
1618
1858
  # batches of rows. Default is 4.
1619
1859
  # @yield [response] the callback for when a batch of rows is inserted
1620
- # @yieldparam [InsertResponse] response the result of the asynchonous
1621
- # insert
1860
+ # @yieldparam [Table::AsyncInserter::Result] result the result of the
1861
+ # asynchronous insert
1622
1862
  #
1623
1863
  # @return [Table::AsyncInserter] Returns an inserter object.
1624
1864
  #
@@ -1628,9 +1868,13 @@ module Google
1628
1868
  # bigquery = Google::Cloud::Bigquery.new
1629
1869
  # dataset = bigquery.dataset "my_dataset"
1630
1870
  # table = dataset.table "my_table"
1631
- # inserter = table.insert_async do |response|
1632
- # log_insert "inserted #{response.insert_count} rows " \
1633
- # "with #{response.error_count} errors"
1871
+ # inserter = table.insert_async do |result|
1872
+ # if result.error?
1873
+ # log_error result.error
1874
+ # else
1875
+ # log_insert "inserted #{result.insert_count} rows " \
1876
+ # "with #{result.error_count} errors"
1877
+ # end
1634
1878
  # end
1635
1879
  #
1636
1880
  # rows = [
@@ -1674,6 +1918,15 @@ module Google
1674
1918
  fail "Must have active connection" unless service
1675
1919
  end
1676
1920
 
1921
+ ##
1922
+ # Ensures the Google::Apis::BigqueryV2::Dataset object has been loaded
1923
+ # from the service.
1924
+ def ensure_gapi!
1925
+ ensure_service!
1926
+ return unless reference?
1927
+ reload!
1928
+ end
1929
+
1677
1930
  def patch_gapi! *attributes
1678
1931
  return if attributes.empty?
1679
1932
  ensure_service!
@@ -1689,17 +1942,7 @@ module Google
1689
1942
  # Load the complete representation of the dataset if it has been
1690
1943
  # only partially loaded by a request to the API list method.
1691
1944
  def ensure_full_data!
1692
- reload_gapi! unless data_complete?
1693
- end
1694
-
1695
- def reload_gapi!
1696
- ensure_service!
1697
- gapi = service.get_dataset dataset_id
1698
- @gapi = gapi
1699
- end
1700
-
1701
- def data_complete?
1702
- @gapi.is_a? Google::Apis::BigqueryV2::Dataset
1945
+ reload! if resource_partial?
1703
1946
  end
1704
1947
 
1705
1948
  def load_storage table_id, url, options = {}