gcloud 0.11.0 → 0.12.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 (121) hide show
  1. checksums.yaml +8 -8
  2. data/AUTHENTICATION.md +3 -3
  3. data/CHANGELOG.md +92 -0
  4. data/OVERVIEW.md +3 -3
  5. data/lib/gcloud.rb +75 -25
  6. data/lib/gcloud/backoff.rb +5 -1
  7. data/lib/gcloud/bigquery.rb +25 -43
  8. data/lib/gcloud/bigquery/copy_job.rb +13 -13
  9. data/lib/gcloud/bigquery/data.rb +20 -16
  10. data/lib/gcloud/bigquery/dataset.rb +202 -177
  11. data/lib/gcloud/bigquery/dataset/access.rb +118 -104
  12. data/lib/gcloud/bigquery/dataset/list.rb +14 -18
  13. data/lib/gcloud/bigquery/extract_job.rb +12 -12
  14. data/lib/gcloud/bigquery/insert_response.rb +12 -14
  15. data/lib/gcloud/bigquery/job.rb +45 -57
  16. data/lib/gcloud/bigquery/job/list.rb +18 -24
  17. data/lib/gcloud/bigquery/load_job.rb +35 -27
  18. data/lib/gcloud/bigquery/project.rb +53 -73
  19. data/lib/gcloud/bigquery/query_data.rb +28 -35
  20. data/lib/gcloud/bigquery/query_job.rb +18 -18
  21. data/lib/gcloud/bigquery/schema.rb +359 -0
  22. data/lib/gcloud/bigquery/service.rb +506 -0
  23. data/lib/gcloud/bigquery/table.rb +185 -266
  24. data/lib/gcloud/bigquery/table/list.rb +15 -19
  25. data/lib/gcloud/bigquery/view.rb +126 -81
  26. data/lib/gcloud/datastore.rb +39 -27
  27. data/lib/gcloud/datastore/commit.rb +2 -2
  28. data/lib/gcloud/datastore/dataset.rb +8 -19
  29. data/lib/gcloud/datastore/dataset/lookup_results.rb +2 -4
  30. data/lib/gcloud/datastore/dataset/query_results.rb +0 -2
  31. data/lib/gcloud/datastore/entity.rb +7 -1
  32. data/lib/gcloud/datastore/errors.rb +5 -27
  33. data/lib/gcloud/datastore/grpc_utils.rb +4 -3
  34. data/lib/gcloud/datastore/key.rb +6 -0
  35. data/lib/gcloud/datastore/service.rb +18 -12
  36. data/lib/gcloud/datastore/transaction.rb +0 -10
  37. data/lib/gcloud/dns.rb +29 -19
  38. data/lib/gcloud/dns/change.rb +10 -15
  39. data/lib/gcloud/dns/change/list.rb +4 -4
  40. data/lib/gcloud/dns/importer.rb +1 -1
  41. data/lib/gcloud/dns/project.rb +32 -49
  42. data/lib/gcloud/dns/record.rb +8 -2
  43. data/lib/gcloud/dns/record/list.rb +4 -4
  44. data/lib/gcloud/dns/service.rb +167 -0
  45. data/lib/gcloud/dns/zone.rb +33 -52
  46. data/lib/gcloud/dns/zone/list.rb +12 -16
  47. data/lib/gcloud/errors.rb +31 -19
  48. data/lib/gcloud/logging.rb +50 -39
  49. data/lib/gcloud/logging/entry.rb +197 -24
  50. data/lib/gcloud/logging/entry/list.rb +0 -2
  51. data/lib/gcloud/logging/logger.rb +1 -1
  52. data/lib/gcloud/logging/metric.rb +3 -9
  53. data/lib/gcloud/logging/metric/list.rb +0 -2
  54. data/lib/gcloud/logging/project.rb +58 -54
  55. data/lib/gcloud/logging/resource_descriptor.rb +2 -2
  56. data/lib/gcloud/logging/resource_descriptor/list.rb +0 -2
  57. data/lib/gcloud/logging/service.rb +32 -23
  58. data/lib/gcloud/logging/sink.rb +8 -14
  59. data/lib/gcloud/logging/sink/list.rb +0 -2
  60. data/lib/gcloud/pubsub.rb +21 -16
  61. data/lib/gcloud/pubsub/policy.rb +204 -0
  62. data/lib/gcloud/pubsub/project.rb +26 -38
  63. data/lib/gcloud/pubsub/service.rb +39 -31
  64. data/lib/gcloud/pubsub/subscription.rb +56 -59
  65. data/lib/gcloud/pubsub/subscription/list.rb +4 -4
  66. data/lib/gcloud/pubsub/topic.rb +69 -66
  67. data/lib/gcloud/pubsub/topic/list.rb +0 -2
  68. data/lib/gcloud/pubsub/topic/{batch.rb → publisher.rb} +15 -2
  69. data/lib/gcloud/resource_manager.rb +27 -26
  70. data/lib/gcloud/resource_manager/manager.rb +19 -39
  71. data/lib/gcloud/resource_manager/policy.rb +211 -0
  72. data/lib/gcloud/resource_manager/project.rb +97 -121
  73. data/lib/gcloud/resource_manager/project/list.rb +7 -7
  74. data/lib/gcloud/resource_manager/project/updater.rb +4 -9
  75. data/lib/gcloud/resource_manager/service.rb +127 -0
  76. data/lib/gcloud/storage.rb +24 -42
  77. data/lib/gcloud/storage/bucket.rb +104 -192
  78. data/lib/gcloud/storage/bucket/acl.rb +47 -143
  79. data/lib/gcloud/storage/bucket/cors.rb +55 -11
  80. data/lib/gcloud/storage/bucket/list.rb +14 -14
  81. data/lib/gcloud/storage/errors.rb +3 -43
  82. data/lib/gcloud/storage/file.rb +114 -111
  83. data/lib/gcloud/storage/file/acl.rb +27 -113
  84. data/lib/gcloud/storage/file/list.rb +21 -21
  85. data/lib/gcloud/storage/project.rb +49 -59
  86. data/lib/gcloud/storage/service.rb +347 -0
  87. data/lib/gcloud/translate.rb +24 -14
  88. data/lib/gcloud/translate/api.rb +12 -21
  89. data/lib/gcloud/translate/detection.rb +5 -5
  90. data/lib/gcloud/translate/language.rb +1 -1
  91. data/lib/gcloud/translate/service.rb +80 -0
  92. data/lib/gcloud/translate/translation.rb +6 -6
  93. data/lib/gcloud/version.rb +1 -1
  94. data/lib/gcloud/vision.rb +24 -15
  95. data/lib/gcloud/vision/annotate.rb +24 -21
  96. data/lib/gcloud/vision/annotation.rb +9 -9
  97. data/lib/gcloud/vision/annotation/entity.rb +11 -11
  98. data/lib/gcloud/vision/annotation/face.rb +25 -25
  99. data/lib/gcloud/vision/annotation/properties.rb +8 -8
  100. data/lib/gcloud/vision/annotation/safe_search.rb +4 -4
  101. data/lib/gcloud/vision/annotation/text.rb +7 -7
  102. data/lib/gcloud/vision/annotation/vertex.rb +1 -1
  103. data/lib/gcloud/vision/image.rb +11 -11
  104. data/lib/gcloud/vision/location.rb +5 -2
  105. data/lib/gcloud/vision/project.rb +14 -16
  106. data/lib/gcloud/vision/service.rb +66 -0
  107. data/lib/google/api_client.rb +0 -0
  108. metadata +27 -24
  109. data/lib/gcloud/bigquery/connection.rb +0 -624
  110. data/lib/gcloud/bigquery/errors.rb +0 -68
  111. data/lib/gcloud/bigquery/table/schema.rb +0 -234
  112. data/lib/gcloud/dns/connection.rb +0 -173
  113. data/lib/gcloud/dns/errors.rb +0 -68
  114. data/lib/gcloud/resource_manager/connection.rb +0 -134
  115. data/lib/gcloud/resource_manager/errors.rb +0 -68
  116. data/lib/gcloud/storage/connection.rb +0 -444
  117. data/lib/gcloud/translate/connection.rb +0 -85
  118. data/lib/gcloud/translate/errors.rb +0 -68
  119. data/lib/gcloud/upload.rb +0 -95
  120. data/lib/gcloud/vision/connection.rb +0 -63
  121. data/lib/gcloud/vision/errors.rb +0 -69
@@ -31,21 +31,21 @@ module Gcloud
31
31
  # The table from which data is copied. This is the table on
32
32
  # which {Table#copy} was called. Returns a {Table} instance.
33
33
  def source
34
- table = config["copy"]["sourceTable"]
34
+ table = @gapi.configuration.copy.source_table
35
35
  return nil unless table
36
- retrieve_table table["projectId"],
37
- table["datasetId"],
38
- table["tableId"]
36
+ retrieve_table table.project_id,
37
+ table.dataset_id,
38
+ table.table_id
39
39
  end
40
40
 
41
41
  ##
42
42
  # The table to which data is copied. Returns a {Table} instance.
43
43
  def destination
44
- table = config["copy"]["destinationTable"]
44
+ table = @gapi.configuration.copy.destination_table
45
45
  return nil unless table
46
- retrieve_table table["projectId"],
47
- table["datasetId"],
48
- table["tableId"]
46
+ retrieve_table table.project_id,
47
+ table.dataset_id,
48
+ table.table_id
49
49
  end
50
50
 
51
51
  ##
@@ -53,7 +53,7 @@ module Gcloud
53
53
  # which provides the following behavior: If the table does not exist,
54
54
  # the copy operation creates the table. This is the default.
55
55
  def create_if_needed?
56
- disp = config["copy"]["createDisposition"]
56
+ disp = @gapi.configuration.copy.create_disposition
57
57
  disp == "CREATE_IF_NEEDED"
58
58
  end
59
59
 
@@ -62,7 +62,7 @@ module Gcloud
62
62
  # provides the following behavior: The table must already exist; if it
63
63
  # does not, an error is returned in the job result.
64
64
  def create_never?
65
- disp = config["copy"]["createDisposition"]
65
+ disp = @gapi.configuration.copy.create_disposition
66
66
  disp == "CREATE_NEVER"
67
67
  end
68
68
 
@@ -71,7 +71,7 @@ module Gcloud
71
71
  # provides the following behavior: If the table already exists, the copy
72
72
  # operation overwrites the table data.
73
73
  def write_truncate?
74
- disp = config["copy"]["writeDisposition"]
74
+ disp = @gapi.configuration.copy.write_disposition
75
75
  disp == "WRITE_TRUNCATE"
76
76
  end
77
77
 
@@ -80,7 +80,7 @@ module Gcloud
80
80
  # provides the following behavior: If the table already exists, the copy
81
81
  # operation appends the data to the table.
82
82
  def write_append?
83
- disp = config["copy"]["writeDisposition"]
83
+ disp = @gapi.configuration.copy.write_disposition
84
84
  disp == "WRITE_APPEND"
85
85
  end
86
86
 
@@ -89,7 +89,7 @@ module Gcloud
89
89
  # provides the following behavior: If the table already exists and
90
90
  # contains data, the job will have an error. This is the default.
91
91
  def write_empty?
92
- disp = config["copy"]["writeDisposition"]
92
+ disp = @gapi.configuration.copy.write_disposition
93
93
  disp == "WRITE_EMPTY"
94
94
  end
95
95
  end
@@ -14,6 +14,7 @@
14
14
 
15
15
 
16
16
  require "delegate"
17
+ require "gcloud/bigquery/service"
17
18
 
18
19
  module Gcloud
19
20
  module Bigquery
@@ -41,23 +42,26 @@ module Gcloud
41
42
  ##
42
43
  # The resource type of the API response.
43
44
  def kind
44
- @gapi["kind"]
45
+ @gapi.kind
45
46
  end
46
47
 
47
48
  ##
48
- # A token used for paging results.
49
- def token
50
- @gapi["pageToken"]
49
+ # The etag.
50
+ def etag
51
+ @gapi.etag
51
52
  end
52
53
 
53
- # A hash of this page of results.
54
- def etag
55
- @gapi["etag"]
54
+ ##
55
+ # A token used for paging results.
56
+ def token
57
+ @gapi.page_token
56
58
  end
57
59
 
58
60
  # The total number of rows in the complete table.
59
61
  def total
60
- @gapi["totalRows"]
62
+ Integer @gapi.total_rows
63
+ rescue
64
+ nil
61
65
  end
62
66
 
63
67
  ##
@@ -174,17 +178,17 @@ module Gcloud
174
178
  # Represents Table Data as a list of positional values (array of arrays).
175
179
  # No type conversion is made, e.g. numbers are formatted as strings.
176
180
  def raw
177
- Array(gapi["rows"]).map { |row| row["f"].map { |f| f["v"] } }
181
+ Array(gapi.rows).map { |row| row.f.map(&:v) }
178
182
  end
179
183
 
180
184
  ##
181
185
  # @private New Data from a response object.
182
- def self.from_response resp, table
183
- formatted_rows = format_rows resp.data["rows"], table.fields
186
+ def self.from_gapi gapi, table
187
+ formatted_rows = format_rows gapi.rows, table.fields
184
188
 
185
189
  data = new formatted_rows
186
190
  data.table = table
187
- data.gapi = resp.data
191
+ data.gapi = gapi
188
192
  data
189
193
  end
190
194
 
@@ -192,11 +196,11 @@ module Gcloud
192
196
  # Disabled rubocop because this implementation will not last.
193
197
 
194
198
  def self.format_rows rows, fields
195
- headers = Array(fields).map { |f| f["name"] }
196
- field_types = Array(fields).map { |f| f["type"] }
199
+ headers = Array(fields).map { |f| f.name }
200
+ field_types = Array(fields).map { |f| f.type }
197
201
 
198
202
  Array(rows).map do |row|
199
- values = row["f"].map { |f| f["v"] }
203
+ values = row.f.map { |f| f.v }
200
204
  formatted_values = format_values field_types, values
201
205
  Hash[headers.zip formatted_values]
202
206
  end
@@ -226,7 +230,7 @@ module Gcloud
226
230
  protected
227
231
 
228
232
  ##
229
- # Raise an error unless an active connection is available.
233
+ # Raise an error unless an active service is available.
230
234
  def ensure_table!
231
235
  fail "Must have active connection" unless table
232
236
  end
@@ -14,11 +14,12 @@
14
14
 
15
15
 
16
16
  require "json"
17
- require "gcloud/bigquery/errors"
17
+ require "gcloud/errors"
18
+ require "gcloud/bigquery/service"
18
19
  require "gcloud/bigquery/table"
19
- require "gcloud/bigquery/table/schema"
20
20
  require "gcloud/bigquery/dataset/list"
21
21
  require "gcloud/bigquery/dataset/access"
22
+ require "google/apis/bigquery_v2"
22
23
 
23
24
  module Gcloud
24
25
  module Bigquery
@@ -43,7 +44,7 @@ module Gcloud
43
44
  class Dataset
44
45
  ##
45
46
  # @private The Connection object.
46
- attr_accessor :connection
47
+ attr_accessor :service
47
48
 
48
49
  ##
49
50
  # @private The Google API Client object.
@@ -52,7 +53,7 @@ module Gcloud
52
53
  ##
53
54
  # @private Create an empty Dataset object.
54
55
  def initialize
55
- @connection = nil
56
+ @service = nil
56
57
  @gapi = {}
57
58
  end
58
59
 
@@ -64,7 +65,7 @@ module Gcloud
64
65
  # @!group Attributes
65
66
  #
66
67
  def dataset_id
67
- @gapi["datasetReference"]["datasetId"]
68
+ @gapi.dataset_reference.dataset_id
68
69
  end
69
70
 
70
71
  ##
@@ -73,7 +74,7 @@ module Gcloud
73
74
  # @!group Attributes
74
75
  #
75
76
  def project_id
76
- @gapi["datasetReference"]["projectId"]
77
+ @gapi.dataset_reference.project_id
77
78
  end
78
79
 
79
80
  ##
@@ -81,8 +82,8 @@ module Gcloud
81
82
  # The gapi fragment containing the Project ID and Dataset ID as a
82
83
  # camel-cased hash.
83
84
  def dataset_ref
84
- dataset_ref = @gapi["datasetReference"]
85
- dataset_ref = dataset_ref.to_hash if dataset_ref.respond_to? :to_hash
85
+ dataset_ref = @gapi.dataset_reference
86
+ dataset_ref = dataset_ref.to_h if dataset_ref.respond_to? :to_h
86
87
  dataset_ref
87
88
  end
88
89
 
@@ -92,7 +93,7 @@ module Gcloud
92
93
  # @!group Attributes
93
94
  #
94
95
  def name
95
- @gapi["friendlyName"]
96
+ @gapi.friendly_name
96
97
  end
97
98
 
98
99
  ##
@@ -101,7 +102,8 @@ module Gcloud
101
102
  # @!group Attributes
102
103
  #
103
104
  def name= new_name
104
- patch_gapi! name: new_name
105
+ @gapi.update! friendly_name: new_name
106
+ patch_gapi! :friendly_name
105
107
  end
106
108
 
107
109
  ##
@@ -111,7 +113,7 @@ module Gcloud
111
113
  #
112
114
  def etag
113
115
  ensure_full_data!
114
- @gapi["etag"]
116
+ @gapi.etag
115
117
  end
116
118
 
117
119
  ##
@@ -121,7 +123,7 @@ module Gcloud
121
123
  #
122
124
  def api_url
123
125
  ensure_full_data!
124
- @gapi["selfLink"]
126
+ @gapi.self_link
125
127
  end
126
128
 
127
129
  ##
@@ -131,7 +133,7 @@ module Gcloud
131
133
  #
132
134
  def description
133
135
  ensure_full_data!
134
- @gapi["description"]
136
+ @gapi.description
135
137
  end
136
138
 
137
139
  ##
@@ -140,7 +142,8 @@ module Gcloud
140
142
  # @!group Attributes
141
143
  #
142
144
  def description= new_description
143
- patch_gapi! description: new_description
145
+ @gapi.update! description: new_description
146
+ patch_gapi! :description
144
147
  end
145
148
 
146
149
  ##
@@ -150,7 +153,11 @@ module Gcloud
150
153
  #
151
154
  def default_expiration
152
155
  ensure_full_data!
153
- @gapi["defaultTableExpirationMs"]
156
+ begin
157
+ Integer @gapi.default_table_expiration_ms
158
+ rescue
159
+ nil
160
+ end
154
161
  end
155
162
 
156
163
  ##
@@ -160,7 +167,8 @@ module Gcloud
160
167
  # @!group Attributes
161
168
  #
162
169
  def default_expiration= new_default_expiration
163
- patch_gapi! default_expiration: new_default_expiration
170
+ @gapi.update! default_table_expiration_ms: new_default_expiration
171
+ patch_gapi! :default_table_expiration_ms
164
172
  end
165
173
 
166
174
  ##
@@ -170,7 +178,11 @@ module Gcloud
170
178
  #
171
179
  def created_at
172
180
  ensure_full_data!
173
- Time.at(@gapi["creationTime"] / 1000.0)
181
+ begin
182
+ Time.at(Integer(@gapi.creation_time) / 1000.0)
183
+ rescue
184
+ nil
185
+ end
174
186
  end
175
187
 
176
188
  ##
@@ -180,7 +192,11 @@ module Gcloud
180
192
  #
181
193
  def modified_at
182
194
  ensure_full_data!
183
- Time.at(@gapi["lastModifiedTime"] / 1000.0)
195
+ begin
196
+ Time.at(Integer(@gapi.last_modified_time) / 1000.0)
197
+ rescue
198
+ nil
199
+ end
184
200
  end
185
201
 
186
202
  ##
@@ -191,12 +207,11 @@ module Gcloud
191
207
  #
192
208
  def location
193
209
  ensure_full_data!
194
- @gapi["location"]
210
+ @gapi.location
195
211
  end
196
212
 
197
213
  ##
198
- # Retrieves the access rules for a Dataset using the Google Cloud
199
- # Datastore API data structure of an array of hashes. The rules can be
214
+ # Retrieves the access rules for a Dataset. The rules can be
200
215
  # updated when passing a block, see {Dataset::Access} for all the methods
201
216
  # available.
202
217
  #
@@ -206,6 +221,8 @@ module Gcloud
206
221
  # @yield [access] a block for setting rules
207
222
  # @yieldparam [Dataset::Access] access the object accepting rules
208
223
  #
224
+ # @return [Gcloud::Bigquery::Dataset::Access]
225
+ #
209
226
  # @example
210
227
  # require "gcloud"
211
228
  #
@@ -239,43 +256,15 @@ module Gcloud
239
256
  #
240
257
  def access
241
258
  ensure_full_data!
242
- g = @gapi
243
- g = g.to_hash if g.respond_to? :to_hash
244
- a = g["access"] ||= []
245
- return a unless block_given?
246
- a2 = Access.new a, dataset_ref
247
- yield a2
248
- self.access = a2.access if a2.changed?
249
- end
250
-
251
- ##
252
- # Sets the access rules for a Dataset using the Google Cloud Datastore API
253
- # data structure of an array of hashes. See [BigQuery Access
254
- # Control](https://cloud.google.com/bigquery/access-control) for more
255
- # information.
256
- #
257
- # This method is provided for advanced usage of managing the access rules.
258
- # Calling {#access} with a block is the preferred way to manage access
259
- # rules.
260
- #
261
- # @example
262
- # require "gcloud"
263
- #
264
- # gcloud = Gcloud.new
265
- # bigquery = gcloud.bigquery
266
- # dataset = bigquery.dataset "my_dataset"
267
- #
268
- # dataset.access = [{"role"=>"OWNER",
269
- # "specialGroup"=>"projectOwners"},
270
- # {"role"=>"WRITER",
271
- # "specialGroup"=>"projectWriters"},
272
- # {"role"=>"READER",
273
- # "specialGroup"=>"projectReaders"},
274
- # {"role"=>"OWNER",
275
- # "userByEmail"=>"123456789-...com"}]
276
- #
277
- def access= new_access
278
- patch_gapi! access: new_access
259
+ access_builder = Access.from_gapi @gapi
260
+ if block_given?
261
+ yield access_builder
262
+ if access_builder.changed?
263
+ @gapi.update! access: access_builder.to_gapi
264
+ patch_gapi! :access
265
+ end
266
+ end
267
+ access_builder.freeze
279
268
  end
280
269
 
281
270
  ##
@@ -300,13 +289,9 @@ module Gcloud
300
289
  # @!group Lifecycle
301
290
  #
302
291
  def delete force: nil
303
- ensure_connection!
304
- resp = connection.delete_dataset dataset_id, force
305
- if resp.success?
306
- true
307
- else
308
- fail ApiError.from_response(resp)
309
- end
292
+ ensure_service!
293
+ service.delete_dataset dataset_id, force
294
+ true
310
295
  end
311
296
 
312
297
  ##
@@ -320,13 +305,11 @@ module Gcloud
320
305
  # length is 1,024 characters.
321
306
  # @param [String] name A descriptive name for the table.
322
307
  # @param [String] description A user-friendly description of the table.
323
- # @param [Hash] schema A hash specifying fields and data types for the
324
- # table. A block may be passed instead (see examples.) For the format of
325
- # this hash, see the [Tables resource
326
- # ](https://cloud.google.com/bigquery/docs/reference/v2/tables#resource)
327
- # .
328
- # @yield [schema] a block for setting the schema
329
- # @yieldparam [Table::Schema] schema the object accepting the schema
308
+ # @param [Array<Schema::Field>] fields An array of Schema::Field objects
309
+ # specifying the schema's data types for the table. The schema may also
310
+ # be configured when passing a block.
311
+ # @yield [table] a block for setting the table
312
+ # @yieldparam [Table] table the table object to be updated
330
313
  #
331
314
  # @return [Gcloud::Bigquery::Table]
332
315
  #
@@ -348,69 +331,77 @@ module Gcloud
348
331
  # name: "My Table",
349
332
  # description: "A description of my table."
350
333
  #
351
- # @example You can define the table's schema using a block.
334
+ # @example The table's schema fields can be passed as an argument.
352
335
  # require "gcloud"
353
336
  #
354
337
  # gcloud = Gcloud.new
355
338
  # bigquery = gcloud.bigquery
356
339
  # dataset = bigquery.dataset "my_dataset"
357
- # table = dataset.create_table "my_table" do |schema|
358
- # schema.string "first_name", mode: :required
359
- # schema.record "cities_lived", mode: :repeated do |nested_schema|
360
- # nested_schema.string "place", mode: :required
361
- # nested_schema.integer "number_of_years", mode: :required
340
+ #
341
+ # schema_fields = [
342
+ # Gcloud::Bigquery::Schema::Field.new(
343
+ # "first_name", :string, mode: :required),
344
+ # Gcloud::Bigquery::Schema::Field.new(
345
+ # "cities_lived", :record, mode: :repeated
346
+ # fields: [
347
+ # Gcloud::Bigquery::Schema::Field.new(
348
+ # "place", :string, mode: :required),
349
+ # Gcloud::Bigquery::Schema::Field.new(
350
+ # "number_of_years", :integer, mode: :required),
351
+ # ])
352
+ # ]
353
+ # table = dataset.create_table "my_table", fields: schema_fields
354
+ #
355
+ # @example Or the table's schema can be configured with the block.
356
+ # require "gcloud"
357
+ #
358
+ # gcloud = Gcloud.new
359
+ # bigquery = gcloud.bigquery
360
+ # dataset = bigquery.dataset "my_dataset"
361
+ #
362
+ # table = dataset.create_table "my_table" do |t|
363
+ # t.schema.string "first_name", mode: :required
364
+ # t.schema.record "cities_lived", mode: :required do |s|
365
+ # s.string "place", mode: :required
366
+ # s.integer "number_of_years", mode: :required
362
367
  # end
363
368
  # end
364
369
  #
365
- # @example You can pass the table's schema as a hash.
370
+ # @example You can define the schema using a nested block.
366
371
  # require "gcloud"
367
372
  #
368
373
  # gcloud = Gcloud.new
369
374
  # bigquery = gcloud.bigquery
370
375
  # dataset = bigquery.dataset "my_dataset"
371
- #
372
- # schema = {
373
- # "fields" => [
374
- # {
375
- # "name" => "first_name",
376
- # "type" => "STRING",
377
- # "mode" => "REQUIRED"
378
- # },
379
- # {
380
- # "name" => "cities_lived",
381
- # "type" => "RECORD",
382
- # "mode" => "REPEATED",
383
- # "fields" => [
384
- # {
385
- # "name" => "place",
386
- # "type" => "STRING",
387
- # "mode" => "REQUIRED"
388
- # },
389
- # {
390
- # "name" => "number_of_years",
391
- # "type" => "INTEGER",
392
- # "mode" => "REQUIRED"
393
- # }
394
- # ]
395
- # }
396
- # ]
397
- # }
398
- # table = dataset.create_table "my_table", schema: schema
376
+ # table = dataset.create_table "my_table" do |t|
377
+ # t.name = "My Table",
378
+ # t.description = "A description of my table."
379
+ # t.schema do |s|
380
+ # s.string "first_name", mode: :required
381
+ # s.record "cities_lived", mode: :repeated do |r|
382
+ # r.string "place", mode: :required
383
+ # r.integer "number_of_years", mode: :required
384
+ # end
385
+ # end
386
+ # end
399
387
  #
400
388
  # @!group Table
401
389
  #
402
- def create_table table_id, name: nil, description: nil, schema: nil
403
- ensure_connection!
404
- if block_given?
405
- if schema
406
- fail ArgumentError, "only schema block or schema option is allowed"
407
- end
408
- schema_builder = Table::Schema.new nil
409
- yield schema_builder
410
- schema = schema_builder.schema if schema_builder.changed?
390
+ def create_table table_id, name: nil, description: nil, fields: nil
391
+ ensure_service!
392
+ new_tb = Google::Apis::BigqueryV2::Table.new(
393
+ table_reference: Google::Apis::BigqueryV2::TableReference.new(
394
+ project_id: project_id, dataset_id: dataset_id, table_id: table_id))
395
+ updater = Table::Updater.new(new_tb).tap do |tb|
396
+ tb.name = name unless name.nil?
397
+ tb.description = description unless description.nil?
398
+ tb.schema.fields = fields unless fields.nil?
411
399
  end
412
- options = { name: name, description: description, schema: schema }
413
- insert_table table_id, options
400
+
401
+ yield updater if block_given?
402
+
403
+ gapi = service.insert_table dataset_id, updater.to_gapi
404
+ Table.from_gapi gapi, service
414
405
  end
415
406
 
416
407
  ##
@@ -448,8 +439,20 @@ module Gcloud
448
439
  # @!group Table
449
440
  #
450
441
  def create_view table_id, query, name: nil, description: nil
451
- options = { query: query, name: name, description: description }
452
- insert_table table_id, options
442
+ new_view_opts = {
443
+ table_reference: Google::Apis::BigqueryV2::TableReference.new(
444
+ project_id: project_id, dataset_id: dataset_id, table_id: table_id
445
+ ),
446
+ friendly_name: name,
447
+ description: description,
448
+ view: Google::Apis::BigqueryV2::ViewDefinition.new(
449
+ query: query
450
+ )
451
+ }.delete_if { |_, v| v.nil? }
452
+ new_view = Google::Apis::BigqueryV2::Table.new new_view_opts
453
+
454
+ gapi = service.insert_table dataset_id, new_view
455
+ Table.from_gapi gapi, service
453
456
  end
454
457
 
455
458
  ##
@@ -472,13 +475,11 @@ module Gcloud
472
475
  # @!group Table
473
476
  #
474
477
  def table table_id
475
- ensure_connection!
476
- resp = connection.get_table dataset_id, table_id
477
- if resp.success?
478
- Table.from_gapi resp.data, connection
479
- else
480
- nil
481
- end
478
+ ensure_service!
479
+ gapi = service.get_table dataset_id, table_id
480
+ Table.from_gapi gapi, service
481
+ rescue Gcloud::NotFoundError
482
+ nil
482
483
  end
483
484
 
484
485
  ##
@@ -516,14 +517,10 @@ module Gcloud
516
517
  # @!group Table
517
518
  #
518
519
  def tables token: nil, max: nil
519
- ensure_connection!
520
+ ensure_service!
520
521
  options = { token: token, max: max }
521
- resp = connection.list_tables dataset_id, options
522
- if resp.success?
523
- Table::List.from_response resp, connection, dataset_id, max
524
- else
525
- fail ApiError.from_response(resp)
526
- end
522
+ gapi = service.list_tables dataset_id, options
523
+ Table::List.from_gapi gapi, service, dataset_id, max
527
524
  end
528
525
 
529
526
  ##
@@ -597,13 +594,9 @@ module Gcloud
597
594
  create: create, write: write, large_results: large_results,
598
595
  flatten: flatten }
599
596
  options[:dataset] ||= self
600
- ensure_connection!
601
- resp = connection.query_job query, options
602
- if resp.success?
603
- Job.from_gapi resp.data, connection
604
- else
605
- fail ApiError.from_response(resp)
606
- end
597
+ ensure_service!
598
+ gapi = service.query_job query, options
599
+ Job.from_gapi gapi, service
607
600
  end
608
601
 
609
602
  ##
@@ -658,13 +651,9 @@ module Gcloud
658
651
  options = { max: max, timeout: timeout, dryrun: dryrun, cache: cache }
659
652
  options[:dataset] ||= dataset_id
660
653
  options[:project] ||= project_id
661
- ensure_connection!
662
- resp = connection.query query, options
663
- if resp.success?
664
- QueryData.from_gapi resp.data, connection
665
- else
666
- fail ApiError.from_response(resp)
667
- end
654
+ ensure_service!
655
+ gapi = service.query query, options
656
+ QueryData.from_gapi gapi, service
668
657
  end
669
658
 
670
659
  ##
@@ -672,35 +661,26 @@ module Gcloud
672
661
  def self.from_gapi gapi, conn
673
662
  new.tap do |f|
674
663
  f.gapi = gapi
675
- f.connection = conn
664
+ f.service = conn
676
665
  end
677
666
  end
678
667
 
679
668
  protected
680
669
 
681
- def insert_table table_id, options
682
- resp = connection.insert_table dataset_id, table_id, options
683
- if resp.success?
684
- Table.from_gapi resp.data, connection
685
- else
686
- fail ApiError.from_response(resp)
687
- end
688
- end
689
-
690
670
  ##
691
- # Raise an error unless an active connection is available.
692
- def ensure_connection!
693
- fail "Must have active connection" unless connection
671
+ # Raise an error unless an active service is available.
672
+ def ensure_service!
673
+ fail "Must have active connection" unless service
694
674
  end
695
675
 
696
- def patch_gapi! options = {}
697
- ensure_connection!
698
- resp = connection.patch_dataset dataset_id, options
699
- if resp.success?
700
- @gapi = resp.data
701
- else
702
- fail ApiError.from_response(resp)
703
- end
676
+ def patch_gapi! *attributes
677
+ return if attributes.empty?
678
+ ensure_service!
679
+ patch_args = Hash[attributes.map do |attr|
680
+ [attr, @gapi.send(attr)]
681
+ end]
682
+ patch_gapi = Google::Apis::BigqueryV2::Dataset.new patch_args
683
+ @gapi = service.patch_dataset dataset_id, patch_gapi
704
684
  end
705
685
 
706
686
  ##
@@ -711,17 +691,62 @@ module Gcloud
711
691
  end
712
692
 
713
693
  def reload_gapi!
714
- ensure_connection!
715
- resp = connection.get_dataset dataset_id
716
- if resp.success?
717
- @gapi = resp.data
718
- else
719
- fail ApiError.from_response(resp)
720
- end
694
+ ensure_service!
695
+ gapi = service.get_dataset dataset_id
696
+ @gapi = gapi
721
697
  end
722
698
 
723
699
  def data_complete?
724
- !@gapi["creationTime"].nil?
700
+ @gapi.is_a? Google::Apis::BigqueryV2::Dataset
701
+ end
702
+
703
+ ##
704
+ # Yielded to a block to accumulate changes for a patch request.
705
+ class Updater < Dataset
706
+ ##
707
+ # A list of attributes that were updated.
708
+ attr_reader :updates
709
+
710
+ ##
711
+ # Create an Updater object.
712
+ def initialize gapi
713
+ @updates = []
714
+ @gapi = gapi
715
+ end
716
+
717
+ def access
718
+ # TODO: make sure to call ensure_full_data! on Dataset#update
719
+ @access ||= Access.from_gapi @gapi
720
+ if block_given?
721
+ yield @access
722
+ check_for_mutated_access!
723
+ end
724
+ # Same as Dataset#access, but not frozen
725
+ @access
726
+ end
727
+
728
+ ##
729
+ # Make sure any access changes are saved
730
+ def check_for_mutated_access!
731
+ return if @access.nil?
732
+ return unless @access.changed?
733
+ @gapi.update! access: @access.to_gapi
734
+ patch_gapi! :access
735
+ end
736
+
737
+ def to_gapi
738
+ check_for_mutated_access!
739
+ @gapi
740
+ end
741
+
742
+ protected
743
+
744
+ ##
745
+ # Queue up all the updates instead of making them.
746
+ def patch_gapi! attribute
747
+ @updates << attribute
748
+ @updates.uniq!
749
+ end
725
750
  end
726
751
  end
727
752
  end