gcloud 0.2.0 → 0.3.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.
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,55 @@
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
+ class Table
19
+ ##
20
+ # Table::List is a special case Array with additional values.
21
+ class List < DelegateClass(::Array)
22
+ ##
23
+ # If not empty, indicates that there are more records that match
24
+ # the request and this value should be passed to continue.
25
+ attr_accessor :token
26
+
27
+ # A hash of this page of results.
28
+ attr_accessor :etag
29
+
30
+ # Total number of jobs in this collection.
31
+ attr_accessor :total
32
+
33
+ ##
34
+ # Create a new Table::List with an array of jobs.
35
+ def initialize arr = []
36
+ super arr
37
+ end
38
+
39
+ ##
40
+ # New Table::List from a response object.
41
+ def self.from_resp resp, conn #:nodoc:
42
+ tables = List.new(Array(resp.data["tables"]).map do |gapi_object|
43
+ Table.from_gapi gapi_object, conn
44
+ end)
45
+ tables.instance_eval do
46
+ @token = resp.data["nextPageToken"]
47
+ @etag = resp.data["etag"]
48
+ @total = resp.data["totalItems"]
49
+ end
50
+ tables
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,419 @@
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/bigquery/data"
17
+ require "gcloud/bigquery/table/list"
18
+ require "gcloud/bigquery/errors"
19
+
20
+ module Gcloud
21
+ module Bigquery
22
+ ##
23
+ # = View
24
+ #
25
+ # A view is a virtual table defined by a SQL query. You can query views in
26
+ # the browser tool, or by using a query job.
27
+ #
28
+ # BigQuery's views are logical views, not materialized views, which means
29
+ # that the query that defines the view is re-executed every time the view is
30
+ # queried. Queries are billed according to the total amount of data in all
31
+ # table fields referenced directly or indirectly by the top-level query.
32
+ #
33
+ # require "gcloud"
34
+ #
35
+ # gcloud = Gcloud.new
36
+ # bigquery = gcloud.bigquery
37
+ # dataset = bigquery.dataset "my_dataset"
38
+ # view = dataset.create_view "my_view",
39
+ # "SELECT name, age FROM [proj:dataset.users]"
40
+ #
41
+ class View
42
+ ##
43
+ # The Connection object.
44
+ attr_accessor :connection #:nodoc:
45
+
46
+ ##
47
+ # The Google API Client object.
48
+ attr_accessor :gapi #:nodoc:
49
+
50
+ ##
51
+ # Create an empty Table object.
52
+ def initialize #:nodoc:
53
+ @connection = nil
54
+ @gapi = {}
55
+ end
56
+
57
+ ##
58
+ # A unique ID for this table.
59
+ # The ID must contain only letters (a-z, A-Z), numbers (0-9),
60
+ # or underscores (_). The maximum length is 1,024 characters.
61
+ #
62
+ # :category: Attributes
63
+ #
64
+ def table_id
65
+ @gapi["tableReference"]["tableId"]
66
+ end
67
+
68
+ ##
69
+ # The ID of the +Dataset+ containing this table.
70
+ #
71
+ # :category: Attributes
72
+ #
73
+ def dataset_id
74
+ @gapi["tableReference"]["datasetId"]
75
+ end
76
+
77
+ ##
78
+ # The ID of the +Project+ containing this table.
79
+ #
80
+ # :category: Attributes
81
+ #
82
+ def project_id
83
+ @gapi["tableReference"]["projectId"]
84
+ end
85
+
86
+ ##
87
+ # The name of the table.
88
+ #
89
+ # :category: Attributes
90
+ #
91
+ def name
92
+ @gapi["friendlyName"]
93
+ end
94
+
95
+ ##
96
+ # Updates the name of the table.
97
+ #
98
+ # :category: Lifecycle
99
+ #
100
+ def name= new_name
101
+ patch_gapi! name: new_name
102
+ end
103
+
104
+ ##
105
+ # A string hash of the dataset.
106
+ #
107
+ # :category: Attributes
108
+ #
109
+ def etag
110
+ ensure_full_data!
111
+ @gapi["etag"]
112
+ end
113
+
114
+ ##
115
+ # A URL that can be used to access the dataset using the REST API.
116
+ #
117
+ # :category: Attributes
118
+ #
119
+ def url
120
+ ensure_full_data!
121
+ @gapi["selfLink"]
122
+ end
123
+
124
+ ##
125
+ # The description of the table.
126
+ #
127
+ # :category: Attributes
128
+ #
129
+ def description
130
+ ensure_full_data!
131
+ @gapi["description"]
132
+ end
133
+
134
+ ##
135
+ # Updates the description of the table.
136
+ #
137
+ # :category: Lifecycle
138
+ #
139
+ def description= new_description
140
+ patch_gapi! description: new_description
141
+ end
142
+
143
+ ##
144
+ # The time when this table was created.
145
+ #
146
+ # :category: Attributes
147
+ #
148
+ def created_at
149
+ ensure_full_data!
150
+ Time.at(@gapi["creationTime"] / 1000.0)
151
+ end
152
+
153
+ ##
154
+ # The time when this table expires.
155
+ # If not present, the table will persist indefinitely.
156
+ # Expired tables will be deleted and their storage reclaimed.
157
+ #
158
+ # :category: Attributes
159
+ #
160
+ def expires_at
161
+ ensure_full_data!
162
+ return nil if @gapi["expirationTime"].nil?
163
+ Time.at(@gapi["expirationTime"] / 1000.0)
164
+ end
165
+
166
+ ##
167
+ # The date when this table was last modified.
168
+ #
169
+ # :category: Attributes
170
+ #
171
+ def modified_at
172
+ ensure_full_data!
173
+ Time.at(@gapi["lastModifiedTime"] / 1000.0)
174
+ end
175
+
176
+ ##
177
+ # Checks if the table's type is "TABLE".
178
+ #
179
+ # :category: Attributes
180
+ #
181
+ def table?
182
+ @gapi["type"] == "TABLE"
183
+ end
184
+
185
+ ##
186
+ # Checks if the table's type is "VIEW".
187
+ #
188
+ # :category: Attributes
189
+ #
190
+ def view?
191
+ @gapi["type"] == "VIEW"
192
+ end
193
+
194
+ ##
195
+ # The geographic location where the table should reside. Possible
196
+ # values include EU and US. The default value is US.
197
+ #
198
+ # :category: Attributes
199
+ #
200
+ def location
201
+ ensure_full_data!
202
+ @gapi["location"]
203
+ end
204
+
205
+ ##
206
+ # The schema of the table.
207
+ #
208
+ # :category: Attributes
209
+ #
210
+ def schema
211
+ ensure_full_data!
212
+ s = @gapi["schema"]
213
+ s = s.to_hash if s.respond_to? :to_hash
214
+ s = {} if s.nil?
215
+ s
216
+ end
217
+
218
+ ##
219
+ # The fields of the table.
220
+ #
221
+ # :category: Attributes
222
+ #
223
+ def fields
224
+ f = schema["fields"]
225
+ f = f.to_hash if f.respond_to? :to_hash
226
+ f = [] if f.nil?
227
+ f
228
+ end
229
+
230
+ ##
231
+ # The names of the columns in the table.
232
+ #
233
+ # :category: Attributes
234
+ #
235
+ def headers
236
+ fields.map { |f| f["name"] }
237
+ end
238
+
239
+ ##
240
+ # The query that executes each time the view is loaded.
241
+ #
242
+ # :category: Attributes
243
+ #
244
+ def query
245
+ @gapi["view"]["query"] if @gapi["view"]
246
+ end
247
+
248
+ ##
249
+ # Updates the query that executes each time the view is loaded.
250
+ # See the BigQuery {Query Reference
251
+ # }[https://cloud.google.com/bigquery/query-reference].
252
+ #
253
+ # === Parameters
254
+ #
255
+ # +new_query+::
256
+ # The query that defines the view. (+String+)
257
+ #
258
+ # === Example
259
+ #
260
+ # require "gcloud"
261
+ #
262
+ # gcloud = Gcloud.new
263
+ # bigquery = gcloud.bigquery
264
+ # dataset = bigquery.dataset "my_dataset"
265
+ # view = dataset.table "my_view"
266
+ #
267
+ # view.query = "SELECT first_name FROM [my_project:my_dataset.my_table]"
268
+ #
269
+ # :category: Lifecycle
270
+ #
271
+ def query= new_query
272
+ patch_gapi! query: new_query
273
+ end
274
+
275
+ ##
276
+ # Runs a query to retrieve all data from the view.
277
+ #
278
+ # === Parameters
279
+ #
280
+ # +options+::
281
+ # An optional Hash for controlling additional behavior. (+Hash+)
282
+ # <code>options[:max]</code>::
283
+ # The maximum number of rows of data to return per page of results.
284
+ # Setting this flag to a small value such as 1000 and then paging
285
+ # through results might improve reliability when the query result set is
286
+ # large. In addition to this limit, responses are also limited to 10 MB.
287
+ # By default, there is no maximum row count, and only the byte limit
288
+ # applies. (+Integer+)
289
+ # <code>options[:timeout]</code>::
290
+ # How long to wait for the query to complete, in milliseconds, before
291
+ # the request times out and returns. Note that this is only a timeout
292
+ # for the request, not the query. If the query takes longer to run than
293
+ # the timeout value, the call returns without any results and with
294
+ # QueryData#complete? set to false. The default value is 10000
295
+ # milliseconds (10 seconds). (+Integer+)
296
+ # <code>options[:dryrun]</code>::
297
+ # If set to +true+, BigQuery doesn't run the job. Instead, if the query
298
+ # is valid, BigQuery returns statistics about the job such as how many
299
+ # bytes would be processed. If the query is invalid, an error returns.
300
+ # The default value is +false+. (+Boolean+)
301
+ # <code>options[:cache]</code>::
302
+ # Whether to look for the result in the query cache. The query cache is
303
+ # a best-effort cache that will be flushed whenever tables in the query
304
+ # are modified. The default value is true. For more information, see
305
+ # {query caching}[https://developers.google.com/bigquery/querying-data].
306
+ # (+Boolean+)
307
+ #
308
+ # === Returns
309
+ #
310
+ # Gcloud::Bigquery::QueryData
311
+ #
312
+ # === Example
313
+ #
314
+ # require "gcloud"
315
+ #
316
+ # gcloud = Gcloud.new
317
+ # bigquery = gcloud.bigquery
318
+ # dataset = bigquery.dataset "my_dataset"
319
+ # view = dataset.table "my_view"
320
+ #
321
+ # data = view.data
322
+ # data.each do |row|
323
+ # puts row["first_name"]
324
+ # end
325
+ # more_data = data.next if data.next?
326
+ #
327
+ # :category: Data
328
+ #
329
+ def data options = {}
330
+ sql = "SELECT * FROM #{@gapi['id']}"
331
+ ensure_connection!
332
+ resp = connection.query sql, options
333
+ if resp.success?
334
+ QueryData.from_gapi resp.data, connection
335
+ else
336
+ fail ApiError.from_response(resp)
337
+ end
338
+ end
339
+
340
+ ##
341
+ # Permanently deletes the table.
342
+ #
343
+ # === Returns
344
+ #
345
+ # +true+ if the table was deleted.
346
+ #
347
+ # === Example
348
+ #
349
+ # require "gcloud"
350
+ #
351
+ # gcloud = Gcloud.new
352
+ # bigquery = gcloud.bigquery
353
+ # dataset = bigquery.dataset "my_dataset"
354
+ # table = dataset.table "my_table"
355
+ #
356
+ # table.delete
357
+ #
358
+ # :category: Lifecycle
359
+ #
360
+ def delete
361
+ ensure_connection!
362
+ resp = connection.delete_table dataset_id, table_id
363
+ if resp.success?
364
+ true
365
+ else
366
+ fail ApiError.from_response(resp)
367
+ end
368
+ end
369
+
370
+ ##
371
+ # New Table from a Google API Client object.
372
+ def self.from_gapi gapi, conn #:nodoc:
373
+ new.tap do |f|
374
+ f.gapi = gapi
375
+ f.connection = conn
376
+ end
377
+ end
378
+
379
+ protected
380
+
381
+ ##
382
+ # Raise an error unless an active connection is available.
383
+ def ensure_connection!
384
+ fail "Must have active connection" unless connection
385
+ end
386
+
387
+ def patch_gapi! options = {}
388
+ ensure_connection!
389
+ resp = connection.patch_table dataset_id, table_id, options
390
+ if resp.success?
391
+ @gapi = resp.data
392
+ else
393
+ fail ApiError.from_response(resp)
394
+ end
395
+ end
396
+
397
+ ##
398
+ # Load the complete representation of the table if it has been
399
+ # only partially loaded by a request to the API list method.
400
+ def ensure_full_data!
401
+ reload_gapi! unless data_complete?
402
+ end
403
+
404
+ def reload_gapi!
405
+ ensure_connection!
406
+ resp = connection.get_table dataset_id, table_id
407
+ if resp.success?
408
+ @gapi = resp.data
409
+ else
410
+ fail ApiError.from_response(resp)
411
+ end
412
+ end
413
+
414
+ def data_complete?
415
+ !@gapi["creationTime"].nil?
416
+ end
417
+ end
418
+ end
419
+ end