gcloud 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +8 -8
  2. data/AUTHENTICATION.md +3 -3
  3. data/CHANGELOG.md +12 -0
  4. data/OVERVIEW.md +30 -0
  5. data/lib/gcloud.rb +126 -9
  6. data/lib/gcloud/bigquery.rb +399 -0
  7. data/lib/gcloud/bigquery/connection.rb +592 -0
  8. data/lib/gcloud/bigquery/copy_job.rb +98 -0
  9. data/lib/gcloud/bigquery/credentials.rb +29 -0
  10. data/lib/gcloud/bigquery/data.rb +134 -0
  11. data/lib/gcloud/bigquery/dataset.rb +662 -0
  12. data/lib/gcloud/bigquery/dataset/list.rb +51 -0
  13. data/lib/gcloud/bigquery/errors.rb +62 -0
  14. data/lib/gcloud/bigquery/extract_job.rb +117 -0
  15. data/lib/gcloud/bigquery/insert_response.rb +80 -0
  16. data/lib/gcloud/bigquery/job.rb +283 -0
  17. data/lib/gcloud/bigquery/job/list.rb +55 -0
  18. data/lib/gcloud/bigquery/load_job.rb +199 -0
  19. data/lib/gcloud/bigquery/project.rb +512 -0
  20. data/lib/gcloud/bigquery/query_data.rb +135 -0
  21. data/lib/gcloud/bigquery/query_job.rb +151 -0
  22. data/lib/gcloud/bigquery/table.rb +827 -0
  23. data/lib/gcloud/bigquery/table/list.rb +55 -0
  24. data/lib/gcloud/bigquery/view.rb +419 -0
  25. data/lib/gcloud/credentials.rb +3 -3
  26. data/lib/gcloud/datastore.rb +15 -3
  27. data/lib/gcloud/datastore/credentials.rb +3 -2
  28. data/lib/gcloud/datastore/dataset.rb +5 -1
  29. data/lib/gcloud/datastore/transaction.rb +1 -1
  30. data/lib/gcloud/pubsub.rb +14 -3
  31. data/lib/gcloud/pubsub/credentials.rb +4 -4
  32. data/lib/gcloud/pubsub/project.rb +5 -1
  33. data/lib/gcloud/pubsub/topic.rb +5 -0
  34. data/lib/gcloud/storage.rb +14 -24
  35. data/lib/gcloud/storage/bucket.rb +10 -4
  36. data/lib/gcloud/storage/credentials.rb +3 -2
  37. data/lib/gcloud/storage/file.rb +8 -1
  38. data/lib/gcloud/storage/project.rb +5 -1
  39. data/lib/gcloud/upload.rb +54 -0
  40. data/lib/gcloud/version.rb +1 -1
  41. metadata +78 -2
@@ -0,0 +1,98 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Gcloud
17
+ module Bigquery
18
+ ##
19
+ # = CopyJob
20
+ #
21
+ # A Job subclass representing a copy operation that may be performed on a
22
+ # Table. A CopyJob instance is created when you call Table#copy.
23
+ #
24
+ # See {Copying an Existing
25
+ # Table}[https://cloud.google.com/bigquery/docs/tables#copyingtable]
26
+ # and the {Jobs API
27
+ # reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs]
28
+ # for details.
29
+ #
30
+ class CopyJob < Job
31
+ ##
32
+ # The table from which data is copied. This is the table on
33
+ # which Table#copy was called. Returns a Table instance.
34
+ def source
35
+ table = config["copy"]["sourceTable"]
36
+ return nil unless table
37
+ retrieve_table table["projectId"],
38
+ table["datasetId"],
39
+ table["tableId"]
40
+ end
41
+
42
+ ##
43
+ # The table to which data is copied. Returns a Table instance.
44
+ def destination
45
+ table = config["copy"]["destinationTable"]
46
+ return nil unless table
47
+ retrieve_table table["projectId"],
48
+ table["datasetId"],
49
+ table["tableId"]
50
+ end
51
+
52
+ ##
53
+ # Checks if the create disposition for the job is +CREATE_IF_NEEDED+,
54
+ # which provides the following behavior: If the table does not exist,
55
+ # the copy operation creates the table. This is the default.
56
+ def create_if_needed?
57
+ disp = config["copy"]["createDisposition"]
58
+ disp == "CREATE_IF_NEEDED"
59
+ end
60
+
61
+ ##
62
+ # Checks if the create disposition for the job is +CREATE_NEVER+, which
63
+ # provides the following behavior: The table must already exist; if it
64
+ # does not, an error is returned in the job result.
65
+ def create_never?
66
+ disp = config["copy"]["createDisposition"]
67
+ disp == "CREATE_NEVER"
68
+ end
69
+
70
+ ##
71
+ # Checks if the write disposition for the job is +WRITE_TRUNCATE+, which
72
+ # provides the following behavior: If the table already exists, the copy
73
+ # operation overwrites the table data.
74
+ def write_truncate?
75
+ disp = config["copy"]["writeDisposition"]
76
+ disp == "WRITE_TRUNCATE"
77
+ end
78
+
79
+ ##
80
+ # Checks if the write disposition for the job is +WRITE_APPEND+, which
81
+ # provides the following behavior: If the table already exists, the copy
82
+ # operation appends the data to the table.
83
+ def write_append?
84
+ disp = config["copy"]["writeDisposition"]
85
+ disp == "WRITE_APPEND"
86
+ end
87
+
88
+ ##
89
+ # Checks if the write disposition for the job is +WRITE_EMPTY+, which
90
+ # provides the following behavior: If the table already exists and
91
+ # contains data, the job will have an error. This is the default.
92
+ def write_empty?
93
+ disp = config["copy"]["writeDisposition"]
94
+ disp == "WRITE_EMPTY"
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,29 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/credentials"
17
+
18
+ module Gcloud
19
+ module Bigquery
20
+ ##
21
+ # Represents the Oauth2 signing logic for Bigquery.
22
+ class Credentials < Gcloud::Credentials #:nodoc:
23
+ SCOPE = ["https://www.googleapis.com/auth/bigquery"]
24
+ PATH_ENV_VARS = %w(BIGQUERY_KEYFILE GCLOUD_KEYFILE GOOGLE_CLOUD_KEYFILE)
25
+ JSON_ENV_VARS = %w(BIGQUERY_KEYFILE_JSON GCLOUD_KEYFILE_JSON
26
+ GOOGLE_CLOUD_KEYFILE_JSON)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,134 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Gcloud
17
+ module Bigquery
18
+ ##
19
+ # = Data
20
+ #
21
+ # Represents Table Data as a list of name/value pairs.
22
+ # Also contains metadata such as +etag+ and +total+.
23
+ class Data < DelegateClass(::Array)
24
+ ##
25
+ # The Table object the data belongs to.
26
+ attr_accessor :table #:nodoc:
27
+
28
+ ##
29
+ # The Google API Client object.
30
+ attr_accessor :gapi #:nodoc:
31
+
32
+ def initialize arr = [] #:nodoc:
33
+ @table = nil
34
+ @gapi = {}
35
+ super arr
36
+ end
37
+
38
+ ##
39
+ # The resource type of the API response.
40
+ def kind
41
+ @gapi["kind"]
42
+ end
43
+
44
+ ##
45
+ # A token used for paging results.
46
+ def token
47
+ @gapi["pageToken"]
48
+ end
49
+
50
+ # A hash of this page of results.
51
+ def etag
52
+ @gapi["etag"]
53
+ end
54
+
55
+ # The total number of rows in the complete table.
56
+ def total
57
+ @gapi["totalRows"]
58
+ end
59
+
60
+ ##
61
+ # Is there a next page of data?
62
+ def next?
63
+ !token.nil?
64
+ end
65
+
66
+ def next
67
+ return nil unless next?
68
+ ensure_table!
69
+ table.data token: token
70
+ end
71
+
72
+ ##
73
+ # Represents Table Data as a list of positional values (array of arrays).
74
+ # No type conversion is made, e.g. numbers are formatted as strings.
75
+ def raw
76
+ Array(gapi["rows"]).map { |row| row["f"].map { |f| f["v"] } }
77
+ end
78
+
79
+ ##
80
+ # New Data from a response object.
81
+ def self.from_response resp, table #:nodoc:
82
+ formatted_rows = format_rows resp.data["rows"], table.fields
83
+
84
+ data = new formatted_rows
85
+ data.table = table
86
+ data.gapi = resp.data
87
+ data
88
+ end
89
+
90
+ # rubocop:disable all
91
+ # Disabled rubocop because this implementation will not last.
92
+
93
+ def self.format_rows rows, fields
94
+ headers = fields.map { |f| f["name"] }
95
+ field_types = fields.map { |f| f["type"] }
96
+
97
+ Array(rows).map do |row|
98
+ values = row["f"].map { |f| f["v"] }
99
+ formatted_values = format_values field_types, values
100
+ Hash[headers.zip formatted_values]
101
+ end
102
+ end
103
+
104
+ def self.format_values field_types, values
105
+ field_types.zip(values).map do |type, value|
106
+ begin
107
+ if value.nil?
108
+ nil
109
+ elsif type == "INTEGER"
110
+ Integer value
111
+ elsif type == "FLOAT"
112
+ Float value
113
+ elsif type == "BOOLEAN"
114
+ (value == "true" ? true : (value == "false" ? false : nil))
115
+ else
116
+ value
117
+ end
118
+ rescue
119
+ value
120
+ end
121
+ end
122
+ end
123
+ # rubocop:enable all
124
+
125
+ protected
126
+
127
+ ##
128
+ # Raise an error unless an active connection is available.
129
+ def ensure_table!
130
+ fail "Must have active connection" unless table
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,662 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "json"
17
+ require "gcloud/bigquery/errors"
18
+ require "gcloud/bigquery/table"
19
+ require "gcloud/bigquery/dataset/list"
20
+
21
+ module Gcloud
22
+ module Bigquery
23
+ ##
24
+ # = Dataset
25
+ #
26
+ # Represents a Dataset. A dataset is a grouping mechanism that holds zero or
27
+ # more tables. Datasets are the lowest level unit of access control; you
28
+ # cannot control access at the table level. A dataset is contained within a
29
+ # specific project.
30
+ #
31
+ # require "gcloud"
32
+ #
33
+ # gcloud = Gcloud.new
34
+ # bigquery = gcloud.bigquery
35
+ #
36
+ # dataset = bigquery.create_dataset "my_dataset",
37
+ # name: "My Dataset"
38
+ # description: "This is my Dataset"
39
+ #
40
+ class Dataset
41
+ ##
42
+ # The Connection object.
43
+ attr_accessor :connection #:nodoc:
44
+
45
+ ##
46
+ # The Google API Client object.
47
+ attr_accessor :gapi #:nodoc:
48
+
49
+ ##
50
+ # Create an empty Dataset object.
51
+ def initialize #:nodoc:
52
+ @connection = nil
53
+ @gapi = {}
54
+ end
55
+
56
+ ##
57
+ # A unique ID for this dataset, without the project name.
58
+ # The ID must contain only letters (a-z, A-Z), numbers (0-9),
59
+ # or underscores (_). The maximum length is 1,024 characters.
60
+ #
61
+ # :category: Attributes
62
+ #
63
+ def dataset_id
64
+ @gapi["datasetReference"]["datasetId"]
65
+ end
66
+
67
+ ##
68
+ # The ID of the project containing this dataset.
69
+ #
70
+ # :category: Attributes
71
+ #
72
+ def project_id
73
+ @gapi["datasetReference"]["projectId"]
74
+ end
75
+
76
+ ##
77
+ # A descriptive name for the dataset.
78
+ #
79
+ # :category: Attributes
80
+ #
81
+ def name
82
+ @gapi["friendlyName"]
83
+ end
84
+
85
+ ##
86
+ # Updates the descriptive name for the dataset.
87
+ #
88
+ # :category: Attributes
89
+ #
90
+ def name= new_name
91
+ patch_gapi! name: new_name
92
+ end
93
+
94
+ ##
95
+ # A string hash of the dataset.
96
+ #
97
+ # :category: Attributes
98
+ #
99
+ def etag
100
+ ensure_full_data!
101
+ @gapi["etag"]
102
+ end
103
+
104
+ ##
105
+ # A URL that can be used to access the dataset using the REST API.
106
+ #
107
+ # :category: Attributes
108
+ #
109
+ def url
110
+ ensure_full_data!
111
+ @gapi["selfLink"]
112
+ end
113
+
114
+ ##
115
+ # A user-friendly description of the dataset.
116
+ #
117
+ # :category: Attributes
118
+ #
119
+ def description
120
+ ensure_full_data!
121
+ @gapi["description"]
122
+ end
123
+
124
+ ##
125
+ # Updates the user-friendly description of the dataset.
126
+ #
127
+ # :category: Attributes
128
+ #
129
+ def description= new_description
130
+ patch_gapi! description: new_description
131
+ end
132
+
133
+ ##
134
+ # The default lifetime of all tables in the dataset, in milliseconds.
135
+ #
136
+ # :category: Attributes
137
+ #
138
+ def default_expiration
139
+ ensure_full_data!
140
+ @gapi["defaultTableExpirationMs"]
141
+ end
142
+
143
+ ##
144
+ # Updates the default lifetime of all tables in the dataset, in
145
+ # milliseconds.
146
+ #
147
+ # :category: Attributes
148
+ #
149
+ def default_expiration= new_default_expiration
150
+ patch_gapi! default_expiration: new_default_expiration
151
+ end
152
+
153
+ ##
154
+ # The time when this dataset was created.
155
+ #
156
+ # :category: Attributes
157
+ #
158
+ def created_at
159
+ ensure_full_data!
160
+ Time.at(@gapi["creationTime"] / 1000.0)
161
+ end
162
+
163
+ ##
164
+ # The date when this dataset or any of its tables was last modified.
165
+ #
166
+ # :category: Attributes
167
+ #
168
+ def modified_at
169
+ ensure_full_data!
170
+ Time.at(@gapi["lastModifiedTime"] / 1000.0)
171
+ end
172
+
173
+ ##
174
+ # The geographic location where the dataset should reside. Possible
175
+ # values include EU and US. The default value is US.
176
+ #
177
+ # :category: Attributes
178
+ #
179
+ def location
180
+ ensure_full_data!
181
+ @gapi["location"]
182
+ end
183
+
184
+ ##
185
+ # Permanently deletes the dataset. The dataset must be empty before it can
186
+ # be deleted unless the +force+ option is set to +true+.
187
+ #
188
+ # === Parameters
189
+ #
190
+ # +options+::
191
+ # An optional Hash for controlling additional behavior. (+Hash+)
192
+ # <code>options[:force]</code>::
193
+ # If +true+, delete all the tables in the dataset. If +false+ and the
194
+ # dataset contains tables, the request will fail. Default is +false+.
195
+ # (+Boolean+)
196
+ #
197
+ # === Returns
198
+ #
199
+ # +true+ if the dataset was deleted.
200
+ #
201
+ # === Example
202
+ #
203
+ # require "gcloud"
204
+ #
205
+ # gcloud = Gcloud.new
206
+ # bigquery = gcloud.bigquery
207
+ #
208
+ # dataset = bigquery.dataset "my_dataset"
209
+ # dataset.delete
210
+ #
211
+ # :category: Lifecycle
212
+ #
213
+ def delete options = {}
214
+ ensure_connection!
215
+ resp = connection.delete_dataset dataset_id, options
216
+ if resp.success?
217
+ true
218
+ else
219
+ fail ApiError.from_response(resp)
220
+ end
221
+ end
222
+
223
+ ##
224
+ # Creates a new table.
225
+ #
226
+ # === Parameters
227
+ #
228
+ # +table_id+::
229
+ # The ID of the table. The ID must contain only letters (a-z, A-Z),
230
+ # numbers (0-9), or underscores (_). The maximum length is 1,024
231
+ # characters. (+String+)
232
+ # +options+::
233
+ # An optional Hash for controlling additional behavior. (+Hash+)
234
+ # <code>options[:name]</code>::
235
+ # A descriptive name for the table. (+String+)
236
+ # <code>options[:description]</code>::
237
+ # A user-friendly description of the table. (+String+)
238
+ # <code>options[:schema]</code>::
239
+ # A schema specifying fields and data types for the table. See the
240
+ # {Tables resource
241
+ # }[https://cloud.google.com/bigquery/docs/reference/v2/tables#resource]
242
+ # for more information. (+Hash+)
243
+ #
244
+ # === Returns
245
+ #
246
+ # Gcloud::Bigquery::Table
247
+ #
248
+ # === Examples
249
+ #
250
+ # require "gcloud"
251
+ #
252
+ # gcloud = Gcloud.new
253
+ # bigquery = gcloud.bigquery
254
+ # dataset = bigquery.dataset "my_dataset"
255
+ # table = dataset.create_table "my_table"
256
+ #
257
+ # A name and description can be provided:
258
+ #
259
+ # require "gcloud"
260
+ #
261
+ # gcloud = Gcloud.new
262
+ # bigquery = gcloud.bigquery
263
+ # dataset = bigquery.dataset "my_dataset"
264
+ #
265
+ # schema = {
266
+ # "fields" => [
267
+ # {
268
+ # "name" => "first_name",
269
+ # "type" => "STRING",
270
+ # "mode" => "REQUIRED"
271
+ # },
272
+ # {
273
+ # "name" => "cities_lived",
274
+ # "type" => "RECORD",
275
+ # "mode" => "REPEATED",
276
+ # "fields" => [
277
+ # {
278
+ # "name" => "place",
279
+ # "type" => "STRING",
280
+ # "mode" => "REQUIRED"
281
+ # },
282
+ # {
283
+ # "name" => "number_of_years",
284
+ # "type" => "INTEGER",
285
+ # "mode" => "REQUIRED"
286
+ # }
287
+ # ]
288
+ # }
289
+ # ]
290
+ # }
291
+ # table = dataset.create_table "my_table",
292
+ # name: "My Table",
293
+ # schema: schema
294
+ #
295
+ # :category: Table
296
+ #
297
+ def create_table table_id, options = {}
298
+ ensure_connection!
299
+ resp = connection.insert_table dataset_id, table_id, options
300
+ if resp.success?
301
+ Table.from_gapi resp.data, connection
302
+ else
303
+ fail ApiError.from_response(resp)
304
+ end
305
+ end
306
+
307
+ ##
308
+ # Creates a new view table from the given query.
309
+ #
310
+ # === Parameters
311
+ #
312
+ # +table_id+::
313
+ # The ID of the view table. The ID must contain only letters (a-z, A-Z),
314
+ # numbers (0-9), or underscores (_). The maximum length is 1,024
315
+ # characters. (+String+)
316
+ # +query+::
317
+ # The query that BigQuery executes when the view is referenced.
318
+ # (+String+)
319
+ # +options+::
320
+ # An optional Hash for controlling additional behavior. (+Hash+)
321
+ # <code>options[:name]</code>::
322
+ # A descriptive name for the table. (+String+)
323
+ # <code>options[:description]</code>::
324
+ # A user-friendly description of the table. (+String+)
325
+ #
326
+ # === Returns
327
+ #
328
+ # Gcloud::Bigquery::View
329
+ #
330
+ # === Examples
331
+ #
332
+ # require "gcloud"
333
+ #
334
+ # gcloud = Gcloud.new
335
+ # bigquery = gcloud.bigquery
336
+ # dataset = bigquery.dataset "my_dataset"
337
+ # view = dataset.create_view "my_view",
338
+ # "SELECT name, age FROM [proj:dataset.users]"
339
+ #
340
+ # A name and description can be provided:
341
+ #
342
+ # require "gcloud"
343
+ #
344
+ # gcloud = Gcloud.new
345
+ # bigquery = gcloud.bigquery
346
+ # dataset = bigquery.dataset "my_dataset"
347
+ # view = dataset.create_view "my_view",
348
+ # "SELECT name, age FROM [proj:dataset.users]",
349
+ # name: "My View", description: "This is my view"
350
+ #
351
+ # :category: Table
352
+ #
353
+ def create_view table_id, query, options = {}
354
+ options[:query] = query
355
+ create_table table_id, options
356
+ end
357
+
358
+ ##
359
+ # Retrieves an existing table by ID.
360
+ #
361
+ # === Parameters
362
+ #
363
+ # +table_id+::
364
+ # The ID of a table. (+String+)
365
+ #
366
+ # === Returns
367
+ #
368
+ # Gcloud::Bigquery::Table or Gcloud::Bigquery::View or nil if the table
369
+ # does not exist
370
+ #
371
+ # === Example
372
+ #
373
+ # require "gcloud"
374
+ #
375
+ # gcloud = Gcloud.new
376
+ # bigquery = gcloud.bigquery
377
+ # dataset = bigquery.dataset "my_dataset"
378
+ # table = dataset.table "my_table"
379
+ # puts table.name
380
+ #
381
+ # :category: Table
382
+ #
383
+ def table table_id
384
+ ensure_connection!
385
+ resp = connection.get_table dataset_id, table_id
386
+ if resp.success?
387
+ Table.from_gapi resp.data, connection
388
+ else
389
+ nil
390
+ end
391
+ end
392
+
393
+ ##
394
+ # Retrieves the list of tables belonging to the dataset.
395
+ #
396
+ # === Parameters
397
+ #
398
+ # +options+::
399
+ # An optional Hash for controlling additional behavior. (+Hash+)
400
+ # <code>options[:token]</code>::
401
+ # A previously-returned page token representing part of the larger set
402
+ # of results to view. (+String+)
403
+ # <code>options[:max]</code>::
404
+ # Maximum number of tables to return. (+Integer+)
405
+ #
406
+ # === Returns
407
+ #
408
+ # Array of Gcloud::Bigquery::Table or Gcloud::Bigquery::View
409
+ # (Gcloud::Bigquery::Table::List)
410
+ #
411
+ # === Examples
412
+ #
413
+ # require "gcloud"
414
+ #
415
+ # gcloud = Gcloud.new
416
+ # bigquery = gcloud.bigquery
417
+ # dataset = bigquery.dataset "my_dataset"
418
+ # tables = dataset.tables
419
+ # tables.each do |table|
420
+ # puts table.name
421
+ # end
422
+ #
423
+ # If you have a significant number of tables, you may need to paginate
424
+ # through them: (See Dataset::List#token)
425
+ #
426
+ # require "gcloud"
427
+ #
428
+ # gcloud = Gcloud.new
429
+ # bigquery = gcloud.bigquery
430
+ # dataset = bigquery.dataset "my_dataset"
431
+ #
432
+ # all_tables = []
433
+ # tmp_tables = dataset.tables
434
+ # while tmp_tables.any? do
435
+ # tmp_tables.each do |table|
436
+ # all_tables << table
437
+ # end
438
+ # # break loop if no more tables available
439
+ # break if tmp_tables.token.nil?
440
+ # # get the next group of tables
441
+ # tmp_tables = dataset.tables token: tmp_tables.token
442
+ # end
443
+ #
444
+ # :category: Table
445
+ #
446
+ def tables options = {}
447
+ ensure_connection!
448
+ resp = connection.list_tables dataset_id, options
449
+ if resp.success?
450
+ Table::List.from_resp resp, connection
451
+ else
452
+ fail ApiError.from_response(resp)
453
+ end
454
+ end
455
+
456
+ ##
457
+ # Queries data using the {asynchronous
458
+ # method}[https://cloud.google.com/bigquery/querying-data].
459
+ #
460
+ # Sets the current dataset as the default dataset in the query. Useful for
461
+ # using unqualified table names.
462
+ #
463
+ # === Parameters
464
+ #
465
+ # +query+::
466
+ # A query string, following the BigQuery {query
467
+ # syntax}[https://cloud.google.com/bigquery/query-reference], of the
468
+ # query to execute. Example: "SELECT count(f1) FROM
469
+ # [myProjectId:myDatasetId.myTableId]". (+String+)
470
+ # <code>options[:priority]</code>::
471
+ # Specifies a priority for the query. Possible values include
472
+ # +INTERACTIVE+ and +BATCH+. The default value is +INTERACTIVE+.
473
+ # (+String+)
474
+ # <code>options[:cache]</code>::
475
+ # Whether to look for the result in the query cache. The query cache is
476
+ # a best-effort cache that will be flushed whenever tables in the query
477
+ # are modified. The default value is +true+. (+Boolean+)
478
+ # <code>options[:table]</code>::
479
+ # The destination table where the query results should be stored. If not
480
+ # present, a new table will be created to store the results. (+Table+)
481
+ # <code>options[:create]</code>::
482
+ # Specifies whether the job is allowed to create new tables. (+String+)
483
+ #
484
+ # The following values are supported:
485
+ # * +needed+ - Create the table if it does not exist.
486
+ # * +never+ - The table must already exist. A 'notFound' error is
487
+ # raised if the table does not exist.
488
+ # <code>options[:write]</code>::
489
+ # Specifies the action that occurs if the destination table already
490
+ # exists. (+String+)
491
+ #
492
+ # The following values are supported:
493
+ # * +truncate+ - BigQuery overwrites the table data.
494
+ # * +append+ - BigQuery appends the data to the table.
495
+ # * +empty+ - A 'duplicate' error is returned in the job result if the
496
+ # table exists and contains data.
497
+ # <code>options[:large_results]</code>::
498
+ # If +true+, allows the query to produce arbitrarily large result tables
499
+ # at a slight cost in performance. Requires <code>options[:table]</code>
500
+ # to be set. (+Boolean+)
501
+ # <code>options[:flatten]</code>::
502
+ # Flattens all nested and repeated fields in the query results. The
503
+ # default value is +true+. <code>options[:large_results]</code> must be
504
+ # +true+ if this is set to +false+. (+Boolean+)
505
+ #
506
+ # === Returns
507
+ #
508
+ # Gcloud::Bigquery::QueryJob
509
+ #
510
+ # === Example
511
+ #
512
+ # require "gcloud"
513
+ #
514
+ # gcloud = Gcloud.new
515
+ # bigquery = gcloud.bigquery
516
+ #
517
+ # job = bigquery.query_job "SELECT name FROM my_table"
518
+ #
519
+ # loop do
520
+ # break if job.done?
521
+ # sleep 1
522
+ # job.refresh!
523
+ # end
524
+ # if !job.failed?
525
+ # job.query_results.each do |row|
526
+ # puts row["name"]
527
+ # end
528
+ # end
529
+ #
530
+ # :category: Data
531
+ #
532
+ def query_job query, options = {}
533
+ options[:dataset] ||= self
534
+ ensure_connection!
535
+ resp = connection.query_job query, options
536
+ if resp.success?
537
+ Job.from_gapi resp.data, connection
538
+ else
539
+ fail ApiError.from_response(resp)
540
+ end
541
+ end
542
+
543
+ ##
544
+ # Queries data using the {synchronous
545
+ # method}[https://cloud.google.com/bigquery/querying-data].
546
+ #
547
+ # Sets the current dataset as the default dataset in the query. Useful for
548
+ # using unqualified table names.
549
+ #
550
+ # === Parameters
551
+ #
552
+ # +query+::
553
+ # A query string, following the BigQuery {query
554
+ # syntax}[https://cloud.google.com/bigquery/query-reference], of the
555
+ # query to execute. Example: "SELECT count(f1) FROM
556
+ # [myProjectId:myDatasetId.myTableId]". (+String+)
557
+ # <code>options[:max]</code>::
558
+ # The maximum number of rows of data to return per page of results.
559
+ # Setting this flag to a small value such as 1000 and then paging
560
+ # through results might improve reliability when the query result set is
561
+ # large. In addition to this limit, responses are also limited to 10 MB.
562
+ # By default, there is no maximum row count, and only the byte limit
563
+ # applies. (+Integer+)
564
+ # <code>options[:timeout]</code>::
565
+ # How long to wait for the query to complete, in milliseconds, before
566
+ # the request times out and returns. Note that this is only a timeout
567
+ # for the request, not the query. If the query takes longer to run than
568
+ # the timeout value, the call returns without any results and with
569
+ # QueryData#complete? set to false. The default value is 10000
570
+ # milliseconds (10 seconds). (+Integer+)
571
+ # <code>options[:dryrun]</code>::
572
+ # If set to +true+, BigQuery doesn't run the job. Instead, if the query
573
+ # is valid, BigQuery returns statistics about the job such as how many
574
+ # bytes would be processed. If the query is invalid, an error returns.
575
+ # The default value is +false+. (+Boolean+)
576
+ # <code>options[:cache]</code>::
577
+ # Whether to look for the result in the query cache. The query cache is
578
+ # a best-effort cache that will be flushed whenever tables in the query
579
+ # are modified. The default value is true. For more information, see
580
+ # {query caching}[https://developers.google.com/bigquery/querying-data].
581
+ # (+Boolean+)
582
+ #
583
+ # === Returns
584
+ #
585
+ # Gcloud::Bigquery::QueryData
586
+ #
587
+ # === Example
588
+ #
589
+ # require "gcloud"
590
+ #
591
+ # gcloud = Gcloud.new
592
+ # bigquery = gcloud.bigquery
593
+ #
594
+ # data = bigquery.query "SELECT name FROM my_table"
595
+ # data.each do |row|
596
+ # puts row["name"]
597
+ # end
598
+ #
599
+ # :category: Data
600
+ #
601
+ def query query, options = {}
602
+ options[:dataset] ||= dataset_id
603
+ options[:project] ||= project_id
604
+ ensure_connection!
605
+ resp = connection.query query, options
606
+ if resp.success?
607
+ QueryData.from_gapi resp.data, connection
608
+ else
609
+ fail ApiError.from_response(resp)
610
+ end
611
+ end
612
+
613
+ ##
614
+ # New Dataset from a Google API Client object.
615
+ def self.from_gapi gapi, conn #:nodoc:
616
+ new.tap do |f|
617
+ f.gapi = gapi
618
+ f.connection = conn
619
+ end
620
+ end
621
+
622
+ protected
623
+
624
+ ##
625
+ # Raise an error unless an active connection is available.
626
+ def ensure_connection!
627
+ fail "Must have active connection" unless connection
628
+ end
629
+
630
+ def patch_gapi! options = {}
631
+ ensure_connection!
632
+ resp = connection.patch_dataset dataset_id, options
633
+ if resp.success?
634
+ @gapi = resp.data
635
+ else
636
+ fail ApiError.from_response(resp)
637
+ end
638
+ end
639
+
640
+ ##
641
+ # Load the complete representation of the dataset if it has been
642
+ # only partially loaded by a request to the API list method.
643
+ def ensure_full_data!
644
+ reload_gapi! unless data_complete?
645
+ end
646
+
647
+ def reload_gapi!
648
+ ensure_connection!
649
+ resp = connection.get_dataset dataset_id
650
+ if resp.success?
651
+ @gapi = resp.data
652
+ else
653
+ fail ApiError.from_response(resp)
654
+ end
655
+ end
656
+
657
+ def data_complete?
658
+ !@gapi["creationTime"].nil?
659
+ end
660
+ end
661
+ end
662
+ end