gcloud 0.12.2 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +5 -13
  2. data/lib/gcloud.rb +27 -456
  3. data/lib/gcloud/bigquery.rb +2 -382
  4. data/lib/gcloud/datastore.rb +2 -576
  5. data/lib/gcloud/dns.rb +2 -321
  6. data/lib/gcloud/logging.rb +1 -322
  7. data/lib/gcloud/pubsub.rb +2 -476
  8. data/lib/gcloud/resource_manager.rb +2 -273
  9. data/lib/gcloud/storage.rb +2 -440
  10. data/lib/gcloud/translate.rb +1 -250
  11. data/lib/gcloud/version.rb +2 -2
  12. data/lib/gcloud/vision.rb +1 -501
  13. metadata +36 -332
  14. data/AUTHENTICATION.md +0 -75
  15. data/CHANGELOG.md +0 -382
  16. data/OVERVIEW.md +0 -259
  17. data/lib/gcloud/backoff.rb +0 -150
  18. data/lib/gcloud/bigquery/copy_job.rb +0 -97
  19. data/lib/gcloud/bigquery/credentials.rb +0 -29
  20. data/lib/gcloud/bigquery/data.rb +0 -239
  21. data/lib/gcloud/bigquery/dataset.rb +0 -753
  22. data/lib/gcloud/bigquery/dataset/access.rb +0 -507
  23. data/lib/gcloud/bigquery/dataset/list.rb +0 -169
  24. data/lib/gcloud/bigquery/extract_job.rb +0 -117
  25. data/lib/gcloud/bigquery/insert_response.rb +0 -81
  26. data/lib/gcloud/bigquery/job.rb +0 -299
  27. data/lib/gcloud/bigquery/job/list.rb +0 -172
  28. data/lib/gcloud/bigquery/load_job.rb +0 -202
  29. data/lib/gcloud/bigquery/project.rb +0 -475
  30. data/lib/gcloud/bigquery/query_data.rb +0 -234
  31. data/lib/gcloud/bigquery/query_job.rb +0 -137
  32. data/lib/gcloud/bigquery/schema.rb +0 -359
  33. data/lib/gcloud/bigquery/service.rb +0 -506
  34. data/lib/gcloud/bigquery/table.rb +0 -1141
  35. data/lib/gcloud/bigquery/table/list.rb +0 -180
  36. data/lib/gcloud/bigquery/view.rb +0 -475
  37. data/lib/gcloud/credentials.rb +0 -129
  38. data/lib/gcloud/datastore/commit.rb +0 -148
  39. data/lib/gcloud/datastore/credentials.rb +0 -35
  40. data/lib/gcloud/datastore/cursor.rb +0 -76
  41. data/lib/gcloud/datastore/dataset.rb +0 -660
  42. data/lib/gcloud/datastore/dataset/lookup_results.rb +0 -219
  43. data/lib/gcloud/datastore/dataset/query_results.rb +0 -386
  44. data/lib/gcloud/datastore/entity.rb +0 -449
  45. data/lib/gcloud/datastore/errors.rb +0 -41
  46. data/lib/gcloud/datastore/gql_query.rb +0 -211
  47. data/lib/gcloud/datastore/grpc_utils.rb +0 -132
  48. data/lib/gcloud/datastore/key.rb +0 -281
  49. data/lib/gcloud/datastore/properties.rb +0 -128
  50. data/lib/gcloud/datastore/query.rb +0 -348
  51. data/lib/gcloud/datastore/service.rb +0 -167
  52. data/lib/gcloud/datastore/transaction.rb +0 -362
  53. data/lib/gcloud/dns/change.rb +0 -158
  54. data/lib/gcloud/dns/change/list.rb +0 -173
  55. data/lib/gcloud/dns/credentials.rb +0 -29
  56. data/lib/gcloud/dns/importer.rb +0 -183
  57. data/lib/gcloud/dns/project.rb +0 -247
  58. data/lib/gcloud/dns/record.rb +0 -170
  59. data/lib/gcloud/dns/record/list.rb +0 -174
  60. data/lib/gcloud/dns/service.rb +0 -167
  61. data/lib/gcloud/dns/zone.rb +0 -759
  62. data/lib/gcloud/dns/zone/list.rb +0 -168
  63. data/lib/gcloud/dns/zone/transaction.rb +0 -176
  64. data/lib/gcloud/errors.rb +0 -206
  65. data/lib/gcloud/gce.rb +0 -56
  66. data/lib/gcloud/grpc_utils.rb +0 -87
  67. data/lib/gcloud/logging/credentials.rb +0 -29
  68. data/lib/gcloud/logging/entry.rb +0 -465
  69. data/lib/gcloud/logging/entry/http_request.rb +0 -141
  70. data/lib/gcloud/logging/entry/list.rb +0 -177
  71. data/lib/gcloud/logging/entry/operation.rb +0 -90
  72. data/lib/gcloud/logging/logger.rb +0 -307
  73. data/lib/gcloud/logging/metric.rb +0 -169
  74. data/lib/gcloud/logging/metric/list.rb +0 -172
  75. data/lib/gcloud/logging/project.rb +0 -642
  76. data/lib/gcloud/logging/resource.rb +0 -84
  77. data/lib/gcloud/logging/resource_descriptor.rb +0 -137
  78. data/lib/gcloud/logging/resource_descriptor/list.rb +0 -174
  79. data/lib/gcloud/logging/service.rb +0 -267
  80. data/lib/gcloud/logging/sink.rb +0 -227
  81. data/lib/gcloud/logging/sink/list.rb +0 -171
  82. data/lib/gcloud/pubsub/credentials.rb +0 -29
  83. data/lib/gcloud/pubsub/message.rb +0 -94
  84. data/lib/gcloud/pubsub/policy.rb +0 -204
  85. data/lib/gcloud/pubsub/project.rb +0 -482
  86. data/lib/gcloud/pubsub/received_message.rb +0 -160
  87. data/lib/gcloud/pubsub/service.rb +0 -334
  88. data/lib/gcloud/pubsub/subscription.rb +0 -565
  89. data/lib/gcloud/pubsub/subscription/list.rb +0 -208
  90. data/lib/gcloud/pubsub/topic.rb +0 -511
  91. data/lib/gcloud/pubsub/topic/list.rb +0 -174
  92. data/lib/gcloud/pubsub/topic/publisher.rb +0 -85
  93. data/lib/gcloud/resource_manager/credentials.rb +0 -30
  94. data/lib/gcloud/resource_manager/manager.rb +0 -266
  95. data/lib/gcloud/resource_manager/policy.rb +0 -211
  96. data/lib/gcloud/resource_manager/project.rb +0 -484
  97. data/lib/gcloud/resource_manager/project/list.rb +0 -167
  98. data/lib/gcloud/resource_manager/project/updater.rb +0 -130
  99. data/lib/gcloud/resource_manager/service.rb +0 -127
  100. data/lib/gcloud/storage/bucket.rb +0 -775
  101. data/lib/gcloud/storage/bucket/acl.rb +0 -810
  102. data/lib/gcloud/storage/bucket/cors.rb +0 -153
  103. data/lib/gcloud/storage/bucket/list.rb +0 -172
  104. data/lib/gcloud/storage/credentials.rb +0 -29
  105. data/lib/gcloud/storage/errors.rb +0 -65
  106. data/lib/gcloud/storage/file.rb +0 -842
  107. data/lib/gcloud/storage/file/acl.rb +0 -425
  108. data/lib/gcloud/storage/file/list.rb +0 -191
  109. data/lib/gcloud/storage/file/verifier.rb +0 -67
  110. data/lib/gcloud/storage/project.rb +0 -316
  111. data/lib/gcloud/storage/service.rb +0 -347
  112. data/lib/gcloud/translate/api.rb +0 -241
  113. data/lib/gcloud/translate/detection.rb +0 -137
  114. data/lib/gcloud/translate/language.rb +0 -69
  115. data/lib/gcloud/translate/service.rb +0 -80
  116. data/lib/gcloud/translate/translation.rb +0 -112
  117. data/lib/gcloud/vision/annotate.rb +0 -224
  118. data/lib/gcloud/vision/annotation.rb +0 -455
  119. data/lib/gcloud/vision/annotation/entity.rb +0 -234
  120. data/lib/gcloud/vision/annotation/face.rb +0 -1750
  121. data/lib/gcloud/vision/annotation/properties.rb +0 -245
  122. data/lib/gcloud/vision/annotation/safe_search.rb +0 -161
  123. data/lib/gcloud/vision/annotation/text.rb +0 -236
  124. data/lib/gcloud/vision/annotation/vertex.rb +0 -108
  125. data/lib/gcloud/vision/credentials.rb +0 -29
  126. data/lib/gcloud/vision/image.rb +0 -590
  127. data/lib/gcloud/vision/location.rb +0 -115
  128. data/lib/gcloud/vision/project.rb +0 -278
  129. data/lib/gcloud/vision/service.rb +0 -66
  130. data/lib/google/api/annotations.rb +0 -14
  131. data/lib/google/api/http.rb +0 -30
  132. data/lib/google/api/label.rb +0 -24
  133. data/lib/google/api/monitored_resource.rb +0 -25
  134. data/lib/google/datastore/v1beta3/datastore.rb +0 -115
  135. data/lib/google/datastore/v1beta3/datastore_services.rb +0 -33
  136. data/lib/google/datastore/v1beta3/entity.rb +0 -63
  137. data/lib/google/datastore/v1beta3/query.rb +0 -128
  138. data/lib/google/devtools/cloudtrace/v1/trace.rb +0 -78
  139. data/lib/google/devtools/cloudtrace/v1/trace_services.rb +0 -32
  140. data/lib/google/example/library/v1/library.rb +0 -91
  141. data/lib/google/example/library/v1/library_services.rb +0 -40
  142. data/lib/google/iam/v1/iam_policy.rb +0 -33
  143. data/lib/google/iam/v1/iam_policy_services.rb +0 -30
  144. data/lib/google/iam/v1/policy.rb +0 -25
  145. data/lib/google/logging/type/http_request.rb +0 -28
  146. data/lib/google/logging/type/log_severity.rb +0 -27
  147. data/lib/google/logging/v2/log_entry.rb +0 -44
  148. data/lib/google/logging/v2/logging.rb +0 -56
  149. data/lib/google/logging/v2/logging_config.rb +0 -59
  150. data/lib/google/logging/v2/logging_config_services.rb +0 -32
  151. data/lib/google/logging/v2/logging_metrics.rb +0 -51
  152. data/lib/google/logging/v2/logging_metrics_services.rb +0 -32
  153. data/lib/google/logging/v2/logging_services.rb +0 -31
  154. data/lib/google/longrunning/operations.rb +0 -50
  155. data/lib/google/longrunning/operations_services.rb +0 -29
  156. data/lib/google/protobuf/descriptor.rb +0 -0
  157. data/lib/google/pubsub/v1/pubsub.rb +0 -129
  158. data/lib/google/pubsub/v1/pubsub_services.rb +0 -56
  159. data/lib/google/pubsub/v1beta2/pubsub.rb +0 -126
  160. data/lib/google/pubsub/v1beta2/pubsub_services.rb +0 -56
  161. data/lib/google/rpc/code.rb +0 -32
  162. data/lib/google/rpc/error_details.rb +0 -61
  163. data/lib/google/rpc/status.rb +0 -19
  164. data/lib/google/type/color.rb +0 -20
  165. data/lib/google/type/date.rb +0 -18
  166. data/lib/google/type/dayofweek.rb +0 -23
  167. data/lib/google/type/latlng.rb +0 -17
  168. data/lib/google/type/money.rb +0 -18
  169. data/lib/google/type/timeofday.rb +0 -19
@@ -1,1141 +0,0 @@
1
- # Copyright 2015 Google Inc. All rights reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
-
16
- require "gcloud/errors"
17
- require "gcloud/bigquery/service"
18
- require "gcloud/bigquery/view"
19
- require "gcloud/bigquery/data"
20
- require "gcloud/bigquery/table/list"
21
- require "gcloud/bigquery/schema"
22
- require "gcloud/bigquery/insert_response"
23
- require "google/apis/bigquery_v2"
24
-
25
- module Gcloud
26
- module Bigquery
27
- ##
28
- # # Table
29
- #
30
- # A named resource representing a BigQuery table that holds zero or more
31
- # records. Every table is defined by a schema that may contain nested and
32
- # repeated fields.
33
- #
34
- # @see https://cloud.google.com/bigquery/preparing-data-for-bigquery
35
- # Preparing Data for BigQuery
36
- #
37
- # @example
38
- # require "gcloud"
39
- #
40
- # gcloud = Gcloud.new
41
- # bigquery = gcloud.bigquery
42
- # dataset = bigquery.dataset "my_dataset"
43
- #
44
- # table = dataset.create_table "my_table" do |schema|
45
- # schema.string "first_name", mode: :required
46
- # schema.record "cities_lived", mode: :repeated do |nested_schema|
47
- # nested_schema.string "place", mode: :required
48
- # nested_schema.integer "number_of_years", mode: :required
49
- # end
50
- # end
51
- #
52
- # row = {
53
- # "first_name" => "Alice",
54
- # "cities_lived" => [
55
- # {
56
- # "place" => "Seattle",
57
- # "number_of_years" => 5
58
- # },
59
- # {
60
- # "place" => "Stockholm",
61
- # "number_of_years" => 6
62
- # }
63
- # ]
64
- # }
65
- # table.insert row
66
- #
67
- class Table
68
- ##
69
- # @private The Service object.
70
- attr_accessor :service
71
-
72
- ##
73
- # @private The Google API Client object.
74
- attr_accessor :gapi
75
-
76
- ##
77
- # @private Create an empty Table object.
78
- def initialize
79
- @service = nil
80
- @gapi = Google::Apis::BigqueryV2::Table.new
81
- end
82
-
83
- ##
84
- # A unique ID for this table.
85
- # The ID must contain only letters (a-z, A-Z), numbers (0-9),
86
- # or underscores (_). The maximum length is 1,024 characters.
87
- #
88
- # @!group Attributes
89
- #
90
- def table_id
91
- @gapi.table_reference.table_id
92
- end
93
-
94
- ##
95
- # The ID of the `Dataset` containing this table.
96
- #
97
- # @!group Attributes
98
- #
99
- def dataset_id
100
- @gapi.table_reference.dataset_id
101
- end
102
-
103
- ##
104
- # The ID of the `Project` containing this table.
105
- #
106
- # @!group Attributes
107
- #
108
- def project_id
109
- @gapi.table_reference.project_id
110
- end
111
-
112
- ##
113
- # @private
114
- # The gapi fragment containing the Project ID, Dataset ID, and Table ID as
115
- # a camel-cased hash.
116
- def table_ref
117
- table_ref = @gapi.table_reference
118
- table_ref = table_ref.to_hash if table_ref.respond_to? :to_hash
119
- table_ref
120
- end
121
-
122
- ##
123
- # The combined Project ID, Dataset ID, and Table ID for this table, in the
124
- # format specified by the [Query
125
- # Reference](https://cloud.google.com/bigquery/query-reference#from):
126
- # `project_name:datasetId.tableId`. To use this value in queries see
127
- # {#query_id}.
128
- #
129
- # @!group Attributes
130
- #
131
- def id
132
- @gapi.id
133
- end
134
-
135
- ##
136
- # The value returned by {#id}, wrapped in square brackets if the Project
137
- # ID contains dashes, as specified by the [Query
138
- # Reference](https://cloud.google.com/bigquery/query-reference#from).
139
- # Useful in queries.
140
- #
141
- # @example
142
- # require "gcloud"
143
- #
144
- # gcloud = Gcloud.new
145
- # bigquery = gcloud.bigquery
146
- # dataset = bigquery.dataset "my_dataset"
147
- # table = dataset.table "my_table"
148
- #
149
- # data = bigquery.query "SELECT name FROM #{table.query_id}"
150
- #
151
- # @!group Attributes
152
- #
153
- def query_id
154
- project_id["-"] ? "[#{id}]" : id
155
- end
156
-
157
- ##
158
- # The name of the table.
159
- #
160
- # @!group Attributes
161
- #
162
- def name
163
- @gapi.friendly_name
164
- end
165
-
166
- ##
167
- # Updates the name of the table.
168
- #
169
- # @!group Attributes
170
- #
171
- def name= new_name
172
- @gapi.update! friendly_name: new_name
173
- patch_gapi! :friendly_name
174
- end
175
-
176
- ##
177
- # A string hash of the dataset.
178
- #
179
- # @!group Attributes
180
- #
181
- def etag
182
- ensure_full_data!
183
- @gapi.etag
184
- end
185
-
186
- ##
187
- # A URL that can be used to access the dataset using the REST API.
188
- #
189
- # @!group Attributes
190
- #
191
- def api_url
192
- ensure_full_data!
193
- @gapi.self_link
194
- end
195
-
196
- ##
197
- # The description of the table.
198
- #
199
- # @!group Attributes
200
- #
201
- def description
202
- ensure_full_data!
203
- @gapi.description
204
- end
205
-
206
- ##
207
- # Updates the description of the table.
208
- #
209
- # @!group Attributes
210
- #
211
- def description= new_description
212
- @gapi.update! description: new_description
213
- patch_gapi! :description
214
- end
215
-
216
- ##
217
- # The number of bytes in the table.
218
- #
219
- # @!group Data
220
- #
221
- def bytes_count
222
- ensure_full_data!
223
- begin
224
- Integer @gapi.num_bytes
225
- rescue
226
- nil
227
- end
228
- end
229
-
230
- ##
231
- # The number of rows in the table.
232
- #
233
- # @!group Data
234
- #
235
- def rows_count
236
- ensure_full_data!
237
- begin
238
- Integer @gapi.num_rows
239
- rescue
240
- nil
241
- end
242
- end
243
-
244
- ##
245
- # The time when this table was created.
246
- #
247
- # @!group Attributes
248
- #
249
- def created_at
250
- ensure_full_data!
251
- begin
252
- Time.at(Integer(@gapi.creation_time) / 1000.0)
253
- rescue
254
- nil
255
- end
256
- end
257
-
258
- ##
259
- # The time when this table expires.
260
- # If not present, the table will persist indefinitely.
261
- # Expired tables will be deleted and their storage reclaimed.
262
- #
263
- # @!group Attributes
264
- #
265
- def expires_at
266
- ensure_full_data!
267
- begin
268
- Time.at(Integer(@gapi.expiration_time) / 1000.0)
269
- rescue
270
- nil
271
- end
272
- end
273
-
274
- ##
275
- # The date when this table was last modified.
276
- #
277
- # @!group Attributes
278
- #
279
- def modified_at
280
- ensure_full_data!
281
- begin
282
- Time.at(Integer(@gapi.last_modified_time) / 1000.0)
283
- rescue
284
- nil
285
- end
286
- end
287
-
288
- ##
289
- # Checks if the table's type is "TABLE".
290
- #
291
- # @!group Attributes
292
- #
293
- def table?
294
- @gapi.type == "TABLE"
295
- end
296
-
297
- ##
298
- # Checks if the table's type is "VIEW".
299
- #
300
- # @!group Attributes
301
- #
302
- def view?
303
- @gapi.type == "VIEW"
304
- end
305
-
306
- ##
307
- # The geographic location where the table should reside. Possible
308
- # values include EU and US. The default value is US.
309
- #
310
- # @!group Attributes
311
- #
312
- def location
313
- ensure_full_data!
314
- @gapi.location
315
- end
316
-
317
- ##
318
- # Returns the table's schema. This method can also be used to set,
319
- # replace, or add to the schema by passing a block. See {Schema} for
320
- # available methods.
321
- #
322
- # @param [Boolean] replace Whether to replace the existing schema with the
323
- # new schema. If `true`, the fields will replace the existing schema. If
324
- # `false`, the fields will be added to the existing schema. When a table
325
- # already contains data, schema changes must be additive. Thus, the
326
- # default value is `false`.
327
- # @yield [schema] a block for setting the schema
328
- # @yieldparam [Schema] schema the object accepting the schema
329
- #
330
- # @return [Gcloud::Bigquery::Schema]
331
- #
332
- # @example
333
- # require "gcloud"
334
- #
335
- # gcloud = Gcloud.new
336
- # bigquery = gcloud.bigquery
337
- # dataset = bigquery.dataset "my_dataset"
338
- # table = dataset.create_table "my_table"
339
- #
340
- # table.schema do |schema|
341
- # schema.string "first_name", mode: :required
342
- # schema.record "cities_lived", mode: :repeated do |nested_schema|
343
- # nested_schema.string "place", mode: :required
344
- # nested_schema.integer "number_of_years", mode: :required
345
- # end
346
- # end
347
- #
348
- # @!group Attributes
349
- #
350
- def schema replace: false
351
- ensure_full_data!
352
- schema_builder = Schema.from_gapi @gapi.schema
353
- if block_given?
354
- if replace
355
- empty_schema = Google::Apis::BigqueryV2::TableSchema.new fields: []
356
- schema_builder = Schema.from_gapi empty_schema
357
- end
358
- yield schema_builder
359
- schema_builder.check_for_mutated_schema!
360
- if schema_builder.changed?
361
- @gapi.schema = schema_builder.to_gapi
362
- patch_gapi! :schema
363
- end
364
- end
365
- schema_builder.freeze
366
- end
367
-
368
- ##
369
- # The fields of the table.
370
- #
371
- # @!group Attributes
372
- #
373
- def fields
374
- schema.fields
375
- end
376
-
377
- ##
378
- # The names of the columns in the table.
379
- #
380
- # @!group Attributes
381
- #
382
- def headers
383
- fields.map(&:name)
384
- end
385
-
386
- ##
387
- # Retrieves data from the table.
388
- #
389
- # @param [String] token Page token, returned by a previous call,
390
- # identifying the result set.
391
- #
392
- # @param [Integer] max Maximum number of results to return.
393
- # @param [Integer] start Zero-based index of the starting row to read.
394
- #
395
- # @return [Gcloud::Bigquery::Data]
396
- #
397
- # @example Paginate rows of data: (See {Data#next})
398
- # require "gcloud"
399
- #
400
- # gcloud = Gcloud.new
401
- # bigquery = gcloud.bigquery
402
- # dataset = bigquery.dataset "my_dataset"
403
- # table = dataset.table "my_table"
404
- #
405
- # data = table.data
406
- # data.each do |row|
407
- # puts row["first_name"]
408
- # end
409
- # if data.next?
410
- # more_data = data.next if data.next?
411
- # end
412
- #
413
- # @example Retrieve all rows of data: (See {Data#all})
414
- # require "gcloud"
415
- #
416
- # gcloud = Gcloud.new
417
- # bigquery = gcloud.bigquery
418
- # dataset = bigquery.dataset "my_dataset"
419
- # table = dataset.table "my_table"
420
- #
421
- # data = table.data
422
- # data.all do |row|
423
- # puts row["first_name"]
424
- # end
425
- #
426
- # @!group Data
427
- #
428
- def data token: nil, max: nil, start: nil
429
- ensure_service!
430
- options = { token: token, max: max, start: start }
431
- gapi = service.list_tabledata dataset_id, table_id, options
432
- Data.from_gapi gapi, self
433
- end
434
-
435
- ##
436
- # Copies the data from the table to another table.
437
- # The destination table argument can also be a string identifier as
438
- # specified by the [Query
439
- # Reference](https://cloud.google.com/bigquery/query-reference#from):
440
- # `project_name:datasetId.tableId`. This is useful for referencing tables
441
- # in other projects and datasets.
442
- #
443
- # @param [Table, String] destination_table The destination for the copied
444
- # data.
445
- # @param [String] create Specifies whether the job is allowed to create
446
- # new tables.
447
- #
448
- # The following values are supported:
449
- #
450
- # * `needed` - Create the table if it does not exist.
451
- # * `never` - The table must already exist. A 'notFound' error is
452
- # raised if the table does not exist.
453
- # @param [String] write Specifies how to handle data already present in
454
- # the destination table. The default value is `empty`.
455
- #
456
- # The following values are supported:
457
- #
458
- # * `truncate` - BigQuery overwrites the table data.
459
- # * `append` - BigQuery appends the data to the table.
460
- # * `empty` - An error will be returned if the destination table already
461
- # contains data.
462
- #
463
- # @return [Gcloud::Bigquery::CopyJob]
464
- #
465
- # @example
466
- # require "gcloud"
467
- #
468
- # gcloud = Gcloud.new
469
- # bigquery = gcloud.bigquery
470
- # dataset = bigquery.dataset "my_dataset"
471
- # table = dataset.table "my_table"
472
- # destination_table = dataset.table "my_destination_table"
473
- #
474
- # copy_job = table.copy destination_table
475
- #
476
- # @example Passing a string identifier for the destination table:
477
- # require "gcloud"
478
- #
479
- # gcloud = Gcloud.new
480
- # bigquery = gcloud.bigquery
481
- # dataset = bigquery.dataset "my_dataset"
482
- # table = dataset.table "my_table"
483
- #
484
- # copy_job = table.copy "other-project:other_dataset.other_table"
485
- #
486
- # @!group Data
487
- #
488
- def copy destination_table, create: nil, write: nil, dryrun: nil
489
- ensure_service!
490
- options = { create: create, write: write, dryrun: dryrun }
491
- gapi = service.copy_table table_ref,
492
- get_table_ref(destination_table),
493
- options
494
- Job.from_gapi gapi, service
495
- end
496
-
497
- ##
498
- # Extract the data from the table to a Google Cloud Storage file.
499
- #
500
- # @see https://cloud.google.com/bigquery/exporting-data-from-bigquery
501
- # Exporting Data From BigQuery
502
- #
503
- # @param [Gcloud::Storage::File, String, Array<String>] extract_url The
504
- # Google Storage file or file URI pattern(s) to which BigQuery should
505
- # extract the table data.
506
- # @param [String] format The exported file format. The default value is
507
- # `csv`.
508
- #
509
- # The following values are supported:
510
- #
511
- # * `csv` - CSV
512
- # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
513
- # * `avro` - [Avro](http://avro.apache.org/)
514
- # @param [String] compression The compression type to use for exported
515
- # files. Possible values include `GZIP` and `NONE`. The default value is
516
- # `NONE`.
517
- # @param [String] delimiter Delimiter to use between fields in the
518
- # exported data. Default is <code>,</code>.
519
- # @param [Boolean] header Whether to print out a header row in the
520
- # results. Default is `true`.
521
- #
522
- #
523
- # @return [Gcloud::Bigquery::ExtractJob]
524
- #
525
- # @example
526
- # require "gcloud"
527
- #
528
- # gcloud = Gcloud.new
529
- # bigquery = gcloud.bigquery
530
- # dataset = bigquery.dataset "my_dataset"
531
- # table = dataset.table "my_table"
532
- #
533
- # extract_job = table.extract "gs://my-bucket/file-name.json",
534
- # format: "json"
535
- #
536
- # @!group Data
537
- #
538
- def extract extract_url, format: nil, compression: nil, delimiter: nil,
539
- header: nil, dryrun: nil
540
- ensure_service!
541
- options = { format: format, compression: compression,
542
- delimiter: delimiter, header: header, dryrun: dryrun }
543
- gapi = service.extract_table table_ref, extract_url, options
544
- Job.from_gapi gapi, service
545
- end
546
-
547
- ##
548
- # Loads data into the table. You can pass a gcloud-ruby storage file path
549
- # or a gcloud-ruby storage file instance. Or, you can upload a file
550
- # directly. See [Loading Data with a POST Request](
551
- # https://cloud.google.com/bigquery/loading-data-post-request#multipart).
552
- #
553
- # A `chunk_size` value can be provided in the options to be used in
554
- # resumable uploads. This value is the number of bytes per chunk and must
555
- # be divisible by 256KB. If it is not divisible by 256KB then it will be
556
- # lowered to the nearest acceptable value.
557
- #
558
- # @param [File, Gcloud::Storage::File, String] file A file or the URI of a
559
- # Google Cloud Storage file containing data to load into the table.
560
- # @param [String] format The exported file format. The default value is
561
- # `csv`.
562
- #
563
- # The following values are supported:
564
- #
565
- # * `csv` - CSV
566
- # * `json` - [Newline-delimited JSON](http://jsonlines.org/)
567
- # * `avro` - [Avro](http://avro.apache.org/)
568
- # * `datastore_backup` - Cloud Datastore backup
569
- # @param [String] create Specifies whether the job is allowed to create
570
- # new tables.
571
- #
572
- # The following values are supported:
573
- #
574
- # * `needed` - Create the table if it does not exist.
575
- # * `never` - The table must already exist. A 'notFound' error is
576
- # raised if the table does not exist.
577
- # @param [String] write Specifies how to handle data already present in
578
- # the table. The default value is `empty`.
579
- #
580
- # The following values are supported:
581
- #
582
- # * `truncate` - BigQuery overwrites the table data.
583
- # * `append` - BigQuery appends the data to the table.
584
- # * `empty` - An error will be returned if the table already contains
585
- # data.
586
- # @param [Array<String>] projection_fields If the `format` option is set
587
- # to `datastore_backup`, indicates which entity properties to load from
588
- # a Cloud Datastore backup. Property names are case sensitive and must
589
- # be top-level properties. If not set, BigQuery loads all properties. If
590
- # any named property isn't found in the Cloud Datastore backup, an
591
- # invalid error is returned.
592
- # @param [Boolean] jagged_rows Accept rows that are missing trailing
593
- # optional columns. The missing values are treated as nulls. If `false`,
594
- # records with missing trailing columns are treated as bad records, and
595
- # if there are too many bad records, an invalid error is returned in the
596
- # job result. The default value is `false`. Only applicable to CSV,
597
- # ignored for other formats.
598
- # @param [Boolean] quoted_newlines Indicates if BigQuery should allow
599
- # quoted data sections that contain newline characters in a CSV file.
600
- # The default value is `false`.
601
- # @param [String] encoding The character encoding of the data. The
602
- # supported values are `UTF-8` or `ISO-8859-1`. The default value is
603
- # `UTF-8`.
604
- # @param [String] delimiter Specifices the separator for fields in a CSV
605
- # file. BigQuery converts the string to `ISO-8859-1` encoding, and then
606
- # uses the first byte of the encoded string to split the data in its
607
- # raw, binary state. Default is <code>,</code>.
608
- # @param [Boolean] ignore_unknown Indicates if BigQuery should allow extra
609
- # values that are not represented in the table schema. If true, the
610
- # extra values are ignored. If false, records with extra columns are
611
- # treated as bad records, and if there are too many bad records, an
612
- # invalid error is returned in the job result. The default value is
613
- # `false`.
614
- #
615
- # The `format` property determines what BigQuery treats as an extra
616
- # value:
617
- #
618
- # * `CSV`: Trailing columns
619
- # * `JSON`: Named values that don't match any column names
620
- # @param [Integer] max_bad_records The maximum number of bad records that
621
- # BigQuery can ignore when running the job. If the number of bad records
622
- # exceeds this value, an invalid error is returned in the job result.
623
- # The default value is `0`, which requires that all records are valid.
624
- # @param [String] quote The value that is used to quote data sections in a
625
- # CSV file. BigQuery converts the string to ISO-8859-1 encoding, and
626
- # then uses the first byte of the encoded string to split the data in
627
- # its raw, binary state. The default value is a double-quote
628
- # <code>"</code>. If your data does not contain quoted sections, set the
629
- # property value to an empty string. If your data contains quoted
630
- # newline characters, you must also set the allowQuotedNewlines property
631
- # to true.
632
- # @param [Integer] skip_leading The number of rows at the top of a CSV
633
- # file that BigQuery will skip when loading the data. The default value
634
- # is `0`. This property is useful if you have header rows in the file
635
- # that should be skipped.
636
- #
637
- # @return [Gcloud::Bigquery::LoadJob]
638
- #
639
- # @example
640
- # require "gcloud"
641
- #
642
- # gcloud = Gcloud.new
643
- # bigquery = gcloud.bigquery
644
- # dataset = bigquery.dataset "my_dataset"
645
- # table = dataset.table "my_table"
646
- #
647
- # load_job = table.load "gs://my-bucket/file-name.csv"
648
- #
649
- # @example Pass a gcloud-ruby storage file instance:
650
- # require "gcloud"
651
- # require "gcloud/storage"
652
- #
653
- # gcloud = Gcloud.new
654
- # bigquery = gcloud.bigquery
655
- # dataset = bigquery.dataset "my_dataset"
656
- # table = dataset.table "my_table"
657
- #
658
- # storage = gcloud.storage
659
- # bucket = storage.bucket "my-bucket"
660
- # file = bucket.file "file-name.csv"
661
- # load_job = table.load file
662
- #
663
- # @example Upload a file directly:
664
- # require "gcloud"
665
- #
666
- # gcloud = Gcloud.new
667
- # bigquery = gcloud.bigquery
668
- # dataset = bigquery.dataset "my_dataset"
669
- # table = dataset.table "my_table"
670
- #
671
- # file = File.open "my_data.csv"
672
- # load_job = table.load file
673
- #
674
- # @!group Data
675
- #
676
- def load file, format: nil, create: nil, write: nil,
677
- projection_fields: nil, jagged_rows: nil, quoted_newlines: nil,
678
- encoding: nil, delimiter: nil, ignore_unknown: nil,
679
- max_bad_records: nil, quote: nil, skip_leading: nil, dryrun: nil
680
- ensure_service!
681
- options = { format: format, create: create, write: write,
682
- projection_fields: projection_fields,
683
- jagged_rows: jagged_rows, quoted_newlines: quoted_newlines,
684
- encoding: encoding, delimiter: delimiter,
685
- ignore_unknown: ignore_unknown,
686
- max_bad_records: max_bad_records, quote: quote,
687
- skip_leading: skip_leading, dryrun: dryrun }
688
- return load_storage(file, options) if storage_url? file
689
- return load_local(file, options) if local_file? file
690
- fail Gcloud::Bigquery::Error, "Don't know how to load #{file}"
691
- end
692
-
693
- ##
694
- # Inserts data into the table for near-immediate querying, without the
695
- # need to complete a #load operation before the data can appear in query
696
- # results.
697
- #
698
- # @see https://cloud.google.com/bigquery/streaming-data-into-bigquery
699
- # Streaming Data Into BigQuery
700
- #
701
- # @param [Hash, Array<Hash>] rows A hash object or array of hash objects
702
- # containing the data.
703
- # @param [Boolean] skip_invalid Insert all valid rows of a request, even
704
- # if invalid rows exist. The default value is `false`, which causes the
705
- # entire request to fail if any invalid rows exist.
706
- # @param [Boolean] ignore_unknown Accept rows that contain values that do
707
- # not match the schema. The unknown values are ignored. Default is
708
- # false, which treats unknown values as errors.
709
- #
710
- # @return [Gcloud::Bigquery::InsertResponse]
711
- #
712
- # @example
713
- # require "gcloud"
714
- #
715
- # gcloud = Gcloud.new
716
- # bigquery = gcloud.bigquery
717
- # dataset = bigquery.dataset "my_dataset"
718
- # table = dataset.table "my_table"
719
- #
720
- # rows = [
721
- # { "first_name" => "Alice", "age" => 21 },
722
- # { "first_name" => "Bob", "age" => 22 }
723
- # ]
724
- # table.insert rows
725
- #
726
- # @!group Data
727
- #
728
- def insert rows, skip_invalid: nil, ignore_unknown: nil
729
- rows = [rows] if rows.is_a? Hash
730
- ensure_service!
731
- options = { skip_invalid: skip_invalid, ignore_unknown: ignore_unknown }
732
- gapi = service.insert_tabledata dataset_id, table_id, rows, options
733
- InsertResponse.from_gapi rows, gapi
734
- end
735
-
736
- ##
737
- # Permanently deletes the table.
738
- #
739
- # @return [Boolean] Returns `true` if the table was deleted.
740
- #
741
- # @example
742
- # require "gcloud"
743
- #
744
- # gcloud = Gcloud.new
745
- # bigquery = gcloud.bigquery
746
- # dataset = bigquery.dataset "my_dataset"
747
- # table = dataset.table "my_table"
748
- #
749
- # table.delete
750
- #
751
- # @!group Lifecycle
752
- #
753
- def delete
754
- ensure_service!
755
- service.delete_table dataset_id, table_id
756
- true
757
- end
758
-
759
- ##
760
- # Reloads the table with current data from the BigQuery service.
761
- #
762
- # @!group Lifecycle
763
- #
764
- def reload!
765
- ensure_service!
766
- gapi = service.get_table dataset_id, table_id
767
- @gapi = gapi
768
- end
769
- alias_method :refresh!, :reload!
770
-
771
- ##
772
- # @private New Table from a Google API Client object.
773
- def self.from_gapi gapi, conn
774
- klass = class_for gapi
775
- klass.new.tap do |f|
776
- f.gapi = gapi
777
- f.service = conn
778
- end
779
- end
780
-
781
- protected
782
-
783
- ##
784
- # Raise an error unless an active service is available.
785
- def ensure_service!
786
- fail "Must have active connection" unless service
787
- end
788
-
789
- def patch_gapi! *attributes
790
- return if attributes.empty?
791
- ensure_service!
792
- patch_args = Hash[attributes.map do |attr|
793
- [attr, @gapi.send(attr)]
794
- end]
795
- patch_gapi = Google::Apis::BigqueryV2::Table.new patch_args
796
- @gapi = service.patch_table dataset_id, table_id, patch_gapi
797
- end
798
-
799
- def self.class_for gapi
800
- return View if gapi.type == "VIEW"
801
- self
802
- end
803
-
804
- def load_storage url, options = {}
805
- # Convert to storage URL
806
- url = url.to_gs_url if url.respond_to? :to_gs_url
807
-
808
- gapi = service.load_table_gs_url dataset_id, table_id, url, options
809
- Job.from_gapi gapi, service
810
- end
811
-
812
- def load_local file, options = {}
813
- # Convert to storage URL
814
- file = file.to_gs_url if file.respond_to? :to_gs_url
815
-
816
- gapi = service.load_table_file dataset_id, table_id, file, options
817
- Job.from_gapi gapi, service
818
- end
819
-
820
- def storage_url? file
821
- file.respond_to?(:to_gs_url) ||
822
- (file.respond_to?(:to_str) &&
823
- file.to_str.downcase.start_with?("gs://"))
824
- end
825
-
826
- def local_file? file
827
- ::File.file? file
828
- rescue
829
- false
830
- end
831
-
832
- ##
833
- # Load the complete representation of the table if it has been
834
- # only partially loaded by a request to the API list method.
835
- def ensure_full_data!
836
- reload_gapi! unless data_complete?
837
- end
838
-
839
- def reload_gapi!
840
- ensure_service!
841
- gapi = service.get_table dataset_id, table_id
842
- @gapi = gapi
843
- end
844
-
845
- def data_complete?
846
- @gapi.is_a? Google::Apis::BigqueryV2::Table
847
- end
848
-
849
- private
850
-
851
- def get_table_ref table
852
- if table.respond_to? :table_ref
853
- table.table_ref
854
- else
855
- Service.table_ref_from_s table, table_ref
856
- end
857
- end
858
-
859
- ##
860
- # Yielded to a block to accumulate changes for a patch request.
861
- class Updater < Table
862
- ##
863
- # A list of attributes that were updated.
864
- attr_reader :updates
865
-
866
- ##
867
- # Create an Updater object.
868
- def initialize gapi
869
- @updates = []
870
- @gapi = gapi
871
- @schema = nil
872
- end
873
-
874
- ##
875
- # Returns the table's schema. This method can also be used to set,
876
- # replace, or add to the schema by passing a block. See {Schema} for
877
- # available methods.
878
- #
879
- # @param [Boolean] replace Whether to replace the existing schema with
880
- # the new schema. If `true`, the fields will replace the existing
881
- # schema. If `false`, the fields will be added to the existing
882
- # schema. When a table already contains data, schema changes must be
883
- # additive. Thus, the default value is `false`.
884
- # @yield [schema] a block for setting the schema
885
- # @yieldparam [Schema] schema the object accepting the schema
886
- #
887
- # @return [Gcloud::Bigquery::Schema]
888
- #
889
- # @example
890
- # require "gcloud"
891
- #
892
- # gcloud = Gcloud.new
893
- # bigquery = gcloud.bigquery
894
- # dataset = bigquery.dataset "my_dataset"
895
- # table = dataset.create_table "my_table" do |t|
896
- # t.name = "My Table",
897
- # t.description = "A description of my table."
898
- # t.schema do |s|
899
- # s.string "first_name", mode: :required
900
- # s.record "cities_lived", mode: :repeated do |r|
901
- # r.string "place", mode: :required
902
- # r.integer "number_of_years", mode: :required
903
- # end
904
- # end
905
- # end
906
- #
907
- # @!group Schema
908
- #
909
- def schema replace: false
910
- # Same as Table#schema, but not frozen
911
- # TODO: make sure to call ensure_full_data! on Dataset#update
912
- @schema ||= Schema.from_gapi @gapi.schema
913
- if block_given?
914
- if replace
915
- @schema = Schema.from_gapi \
916
- Google::Apis::BigqueryV2::TableSchema.new(fields: [])
917
- end
918
- yield @schema
919
- check_for_mutated_schema!
920
- end
921
- # Do not freeze on updater, allow modifications
922
- @schema
923
- end
924
-
925
- ##
926
- # Adds a string field to the schema.
927
- #
928
- # See {Schema#string}.
929
- #
930
- # @param [String] name The field name. The name must contain only
931
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
932
- # start with a letter or underscore. The maximum length is 128
933
- # characters.
934
- # @param [String] description A description of the field.
935
- # @param [Symbol] mode The field's mode. The possible values are
936
- # `:nullable`, `:required`, and `:repeated`. The default value is
937
- # `:nullable`.
938
- #
939
- # @example
940
- # require "gcloud"
941
- #
942
- # gcloud = Gcloud.new
943
- # bigquery = gcloud.bigquery
944
- # dataset = bigquery.dataset "my_dataset"
945
- # table = dataset.create_table "my_table" do |schema|
946
- # schema.string "first_name", mode: :required
947
- # end
948
- #
949
- # @!group Schema
950
- def string name, description: nil, mode: :nullable
951
- schema.string name, description: description, mode: mode
952
- end
953
-
954
- ##
955
- # Adds an integer field to the schema.
956
- #
957
- # See {Schema#integer}.
958
- #
959
- # @param [String] name The field name. The name must contain only
960
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
961
- # start with a letter or underscore. The maximum length is 128
962
- # characters.
963
- # @param [String] description A description of the field.
964
- # @param [Symbol] mode The field's mode. The possible values are
965
- # `:nullable`, `:required`, and `:repeated`. The default value is
966
- # `:nullable`.
967
- #
968
- # @example
969
- # require "gcloud"
970
- #
971
- # gcloud = Gcloud.new
972
- # bigquery = gcloud.bigquery
973
- # dataset = bigquery.dataset "my_dataset"
974
- # table = dataset.create_table "my_table" do |schema|
975
- # schema.integer "age", mode: :required
976
- # end
977
- #
978
- # @!group Schema
979
- def integer name, description: nil, mode: :nullable
980
- schema.integer name, description: description, mode: mode
981
- end
982
-
983
- ##
984
- # Adds a floating-point number field to the schema.
985
- #
986
- # See {Schema#float}.
987
- #
988
- # @param [String] name The field name. The name must contain only
989
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
990
- # start with a letter or underscore. The maximum length is 128
991
- # characters.
992
- # @param [String] description A description of the field.
993
- # @param [Symbol] mode The field's mode. The possible values are
994
- # `:nullable`, `:required`, and `:repeated`. The default value is
995
- # `:nullable`.
996
- #
997
- # @example
998
- # require "gcloud"
999
- #
1000
- # gcloud = Gcloud.new
1001
- # bigquery = gcloud.bigquery
1002
- # dataset = bigquery.dataset "my_dataset"
1003
- # table = dataset.create_table "my_table" do |schema|
1004
- # schema.float "price", mode: :required
1005
- # end
1006
- #
1007
- # @!group Schema
1008
- def float name, description: nil, mode: :nullable
1009
- schema.float name, description: description, mode: mode
1010
- end
1011
-
1012
- ##
1013
- # Adds a boolean field to the schema.
1014
- #
1015
- # See {Schema#boolean}.
1016
- #
1017
- # @param [String] name The field name. The name must contain only
1018
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
1019
- # start with a letter or underscore. The maximum length is 128
1020
- # characters.
1021
- # @param [String] description A description of the field.
1022
- # @param [Symbol] mode The field's mode. The possible values are
1023
- # `:nullable`, `:required`, and `:repeated`. The default value is
1024
- # `:nullable`.
1025
- #
1026
- # @example
1027
- # require "gcloud"
1028
- #
1029
- # gcloud = Gcloud.new
1030
- # bigquery = gcloud.bigquery
1031
- # dataset = bigquery.dataset "my_dataset"
1032
- # table = dataset.create_table "my_table" do |schema|
1033
- # schema.boolean "active", mode: :required
1034
- # end
1035
- #
1036
- # @!group Schema
1037
- def boolean name, description: nil, mode: :nullable
1038
- schema.boolean name, description: description, mode: mode
1039
- end
1040
-
1041
- ##
1042
- # Adds a timestamp field to the schema.
1043
- #
1044
- # See {Schema#timestamp}.
1045
- #
1046
- # @param [String] name The field name. The name must contain only
1047
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
1048
- # start with a letter or underscore. The maximum length is 128
1049
- # characters.
1050
- # @param [String] description A description of the field.
1051
- # @param [Symbol] mode The field's mode. The possible values are
1052
- # `:nullable`, `:required`, and `:repeated`. The default value is
1053
- # `:nullable`.
1054
- #
1055
- # @example
1056
- # require "gcloud"
1057
- #
1058
- # gcloud = Gcloud.new
1059
- # bigquery = gcloud.bigquery
1060
- # dataset = bigquery.dataset "my_dataset"
1061
- # table = dataset.create_table "my_table" do |schema|
1062
- # schema.timestamp "creation_date", mode: :required
1063
- # end
1064
- #
1065
- # @!group Schema
1066
- def timestamp name, description: nil, mode: :nullable
1067
- schema.timestamp name, description: description, mode: mode
1068
- end
1069
-
1070
- ##
1071
- # Adds a record field to the schema. A block must be passed describing
1072
- # the nested fields of the record. For more information about nested
1073
- # and repeated records, see [Preparing Data for BigQuery
1074
- # ](https://cloud.google.com/bigquery/preparing-data-for-bigquery).
1075
- #
1076
- # See {Schema#record}.
1077
- #
1078
- # @param [String] name The field name. The name must contain only
1079
- # letters (a-z, A-Z), numbers (0-9), or underscores (_), and must
1080
- # start with a letter or underscore. The maximum length is 128
1081
- # characters.
1082
- # @param [String] description A description of the field.
1083
- # @param [Symbol] mode The field's mode. The possible values are
1084
- # `:nullable`, `:required`, and `:repeated`. The default value is
1085
- # `:nullable`.
1086
- # @yield [nested_schema] a block for setting the nested schema
1087
- # @yieldparam [Schema] nested_schema the object accepting the
1088
- # nested schema
1089
- #
1090
- # @example
1091
- # require "gcloud"
1092
- #
1093
- # gcloud = Gcloud.new
1094
- # bigquery = gcloud.bigquery
1095
- # dataset = bigquery.dataset "my_dataset"
1096
- # table = dataset.create_table "my_table" do |schema|
1097
- # schema.record "cities_lived", mode: :repeated do |cities_lived|
1098
- # cities_lived.string "place", mode: :required
1099
- # cities_lived.integer "number_of_years", mode: :required
1100
- # end
1101
- # end
1102
- #
1103
- # @!group Schema
1104
- #
1105
- def record name, description: nil, mode: nil, &block
1106
- schema.record name, description: description, mode: mode, &block
1107
- end
1108
-
1109
- ##
1110
- # Make sure any access changes are saved
1111
- def check_for_mutated_schema!
1112
- return if @schema.nil?
1113
- @schema.check_for_mutated_schema!
1114
- return unless @schema.changed?
1115
- @gapi.schema = @schema.to_gapi
1116
- patch_gapi! :schema
1117
- end
1118
-
1119
- def to_gapi
1120
- check_for_mutated_schema!
1121
- @gapi
1122
- end
1123
-
1124
- protected
1125
-
1126
- ##
1127
- # Change to a NOOP
1128
- def ensure_full_data!
1129
- # Do nothing because we trust the gapi is full before we get here.
1130
- end
1131
-
1132
- ##
1133
- # Queue up all the updates instead of making them.
1134
- def patch_gapi! attribute
1135
- @updates << attribute
1136
- @updates.uniq!
1137
- end
1138
- end
1139
- end
1140
- end
1141
- end