azure-storage 0.10.0.preview

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/lib/azure/storage.rb +58 -0
  3. data/lib/azure/storage/autoload.rb +71 -0
  4. data/lib/azure/storage/blob/append.rb +154 -0
  5. data/lib/azure/storage/blob/blob.rb +821 -0
  6. data/lib/azure/storage/blob/blob_service.rb +510 -0
  7. data/lib/azure/storage/blob/block.rb +264 -0
  8. data/lib/azure/storage/blob/container.rb +552 -0
  9. data/lib/azure/storage/blob/page.rb +380 -0
  10. data/lib/azure/storage/blob/serialization.rb +297 -0
  11. data/lib/azure/storage/client.rb +185 -0
  12. data/lib/azure/storage/configurable.rb +137 -0
  13. data/lib/azure/storage/core.rb +33 -0
  14. data/lib/azure/storage/core/auth/shared_access_signature.rb +27 -0
  15. data/lib/azure/storage/core/auth/shared_access_signature_generator.rb +194 -0
  16. data/lib/azure/storage/core/auth/shared_access_signature_signer.rb +49 -0
  17. data/lib/azure/storage/core/auth/shared_key.rb +125 -0
  18. data/lib/azure/storage/core/auth/shared_key_lite.rb +55 -0
  19. data/lib/azure/storage/core/auth/signer.rb +60 -0
  20. data/lib/azure/storage/core/autoload.rb +35 -0
  21. data/lib/azure/storage/core/client_options.rb +334 -0
  22. data/lib/azure/storage/core/client_options_error.rb +39 -0
  23. data/lib/azure/storage/core/constants.rb +1077 -0
  24. data/lib/azure/storage/core/error.rb +47 -0
  25. data/lib/azure/storage/core/filtered_service.rb +54 -0
  26. data/lib/azure/storage/core/http/debug_filter.rb +45 -0
  27. data/lib/azure/storage/core/http/http_error.rb +95 -0
  28. data/lib/azure/storage/core/http/http_filter.rb +62 -0
  29. data/lib/azure/storage/core/http/http_request.rb +182 -0
  30. data/lib/azure/storage/core/http/http_response.rb +105 -0
  31. data/lib/azure/storage/core/http/retry_policy.rb +83 -0
  32. data/lib/azure/storage/core/http/signer_filter.rb +42 -0
  33. data/lib/azure/storage/core/http_client.rb +63 -0
  34. data/lib/azure/storage/core/service.rb +55 -0
  35. data/lib/azure/storage/core/signed_service.rb +54 -0
  36. data/lib/azure/storage/core/sr.rb +83 -0
  37. data/lib/azure/storage/core/utility.rb +254 -0
  38. data/lib/azure/storage/queue/message.rb +39 -0
  39. data/lib/azure/storage/queue/queue.rb +37 -0
  40. data/lib/azure/storage/queue/queue_service.rb +580 -0
  41. data/lib/azure/storage/queue/serialization.rb +113 -0
  42. data/lib/azure/storage/service/access_policy.rb +35 -0
  43. data/lib/azure/storage/service/cors.rb +36 -0
  44. data/lib/azure/storage/service/cors_rule.rb +46 -0
  45. data/lib/azure/storage/service/enumeration_results.rb +30 -0
  46. data/lib/azure/storage/service/logging.rb +45 -0
  47. data/lib/azure/storage/service/metrics.rb +43 -0
  48. data/lib/azure/storage/service/retention_policy.rb +35 -0
  49. data/lib/azure/storage/service/serialization.rb +308 -0
  50. data/lib/azure/storage/service/signed_identifier.rb +39 -0
  51. data/lib/azure/storage/service/storage_service.rb +131 -0
  52. data/lib/azure/storage/service/storage_service_properties.rb +46 -0
  53. data/lib/azure/storage/table/auth/shared_key.rb +68 -0
  54. data/lib/azure/storage/table/auth/shared_key_lite.rb +53 -0
  55. data/lib/azure/storage/table/batch.rb +339 -0
  56. data/lib/azure/storage/table/batch_response.rb +127 -0
  57. data/lib/azure/storage/table/edmtype.rb +136 -0
  58. data/lib/azure/storage/table/entity.rb +40 -0
  59. data/lib/azure/storage/table/guid.rb +33 -0
  60. data/lib/azure/storage/table/query.rb +121 -0
  61. data/lib/azure/storage/table/serialization.rb +117 -0
  62. data/lib/azure/storage/table/table_service.rb +571 -0
  63. data/lib/azure/storage/version.rb +46 -0
  64. metadata +329 -0
@@ -0,0 +1,117 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+ require 'azure/storage/service/serialization'
25
+
26
+ require 'azure/storage/table/guid'
27
+ require 'azure/storage/table/edmtype'
28
+
29
+ require 'time'
30
+ require 'date'
31
+
32
+ module Azure::Storage
33
+ module Table
34
+ module Serialization
35
+ include Azure::Storage::Service::Serialization
36
+
37
+ def self.hash_to_entry_xml(hash, id=nil, xml=Nokogiri::XML::Builder.new(:encoding => 'UTF-8'))
38
+ entry_namespaces = {
39
+ 'xmlns' => 'http://www.w3.org/2005/Atom',
40
+ 'xmlns:m' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata',
41
+ 'xmlns:d' => 'http://schemas.microsoft.com/ado/2007/08/dataservices'
42
+ }
43
+
44
+ xml.entry entry_namespaces do |entry|
45
+ id ? entry.id(id): entry.id
46
+ entry.updated Time.now.xmlschema
47
+ entry.title
48
+ entry.author do |author|
49
+ author.name
50
+ end
51
+ hash_to_content_xml(hash, entry)
52
+ end
53
+
54
+ xml
55
+ end
56
+
57
+ def self.hash_to_content_xml(hash, xml=Nokogiri::XML::Builder.new(:encoding => 'UTF-8'))
58
+ xml.send('content', :type => 'application/xml') do |content|
59
+ content.send('m:properties') do |properties|
60
+ hash.each do |key, val|
61
+ key = key.encode('UTF-8') if key.is_a? String and !key.encoding.names.include?('BINARY')
62
+ val = val.encode('UTF-8') if val.is_a? String and !val.encoding.names.include?('BINARY')
63
+
64
+ type = Azure::Storage::Table::EdmType.property_type(val)
65
+ attributes = {}
66
+ attributes['m:type'] = type unless type.nil? || type.empty?
67
+
68
+ if val.nil?
69
+ attributes['m:null'] = 'true'
70
+ properties.send("d:#{key}", attributes)
71
+ else
72
+ properties.send("d:#{key}", Azure::Storage::Table::EdmType.serialize_value(type, val), attributes)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ xml
79
+ end
80
+
81
+ def self.entries_from_feed_xml(xml)
82
+ xml = slopify(xml)
83
+ expect_node('feed', xml)
84
+
85
+ return nil unless (xml > 'entry').any?
86
+
87
+ results = []
88
+
89
+ if (xml > 'entry').count == 0
90
+ results.push hash_from_entry_xml((xml > 'entry'))
91
+ else
92
+ (xml > 'entry').each do |entry|
93
+ results.push hash_from_entry_xml(entry)
94
+ end
95
+ end
96
+
97
+ results
98
+ end
99
+
100
+ def self.hash_from_entry_xml(xml)
101
+ xml = slopify(xml)
102
+ expect_node('entry', xml)
103
+ result = {}
104
+ result[:etag] = xml['etag']
105
+ result[:updated] = Time.parse((xml > 'updated').text) if (xml > 'updated').any?
106
+ properties = {}
107
+ if (xml > 'content').any?
108
+ (xml > 'content').first.first_element_child.element_children.each do |prop|
109
+ properties[prop.name] = prop.text != '' ? Azure::Storage::Table::EdmType.unserialize_query_value(prop.text, prop['m:type']) : prop['null'] ? nil : ''
110
+ end
111
+ end
112
+ result[:properties] = properties
113
+ result
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,571 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # The MIT License(MIT)
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files(the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions :
12
+
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #--------------------------------------------------------------------------
24
+ require 'azure/storage/service/storage_service'
25
+
26
+ require 'azure/storage/table/auth/shared_key'
27
+ require 'azure/storage/table/serialization'
28
+ require 'azure/storage/table/entity'
29
+
30
+ module Azure::Storage
31
+ module Table
32
+ class TableService < Azure::Storage::Service::StorageService
33
+
34
+ def initialize(options = {})
35
+ client_config = options[:client] || Azure::Storage
36
+ signer = options[:signer] || Auth::SharedKey.new(client_config.storage_account_name, client_config.storage_access_key)
37
+ super(signer, client_config.storage_account_name, options)
38
+ @host = client.storage_table_host
39
+ end
40
+
41
+ # Public: Creates new table in the storage account
42
+ #
43
+ # ==== Attributes
44
+ #
45
+ # * +table_name+ - String. The table name
46
+ # * +options+ - Hash. Optional parameters.
47
+ #
48
+ # ==== Options
49
+ #
50
+ # Accepted key/value pairs in options parameter are:
51
+ #
52
+ # * +:timeout+ - Integer. A timeout in seconds.
53
+ #
54
+ # See http://msdn.microsoft.com/en-us/library/azure/dd135729
55
+ #
56
+ # @return [nil] on success
57
+ def create_table(table_name, options={})
58
+ query = { }
59
+ query['timeout'] = options[:timeout].to_s if options[:timeout]
60
+
61
+ body = Azure::Storage::Table::Serialization.hash_to_entry_xml({"TableName" => table_name}).to_xml
62
+ call(:post, collection_uri(query), body)
63
+ nil
64
+ end
65
+
66
+ # Public: Deletes the specified table and any data it contains.
67
+ #
68
+ # ==== Attributes
69
+ #
70
+ # * +table_name+ - String. The table name
71
+ # * +options+ - Hash. Optional parameters.
72
+ #
73
+ # ==== Options
74
+ #
75
+ # Accepted key/value pairs in options parameter are:
76
+ # * +:timeout+ - Integer. A timeout in seconds.
77
+ #
78
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179387
79
+ #
80
+ # Returns nil on success
81
+ def delete_table(table_name, options={})
82
+ query = { }
83
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
84
+
85
+ call(:delete, table_uri(table_name, query))
86
+ nil
87
+ end
88
+
89
+ # Public: Gets the table.
90
+ #
91
+ # ==== Attributes
92
+ #
93
+ # * +table_name+ - String. The table name
94
+ # * +options+ - Hash. Optional parameters.
95
+ #
96
+ # ==== Options
97
+ #
98
+ # Accepted key/value pairs in options parameter are:
99
+ # * +:timeout+ - Integer. A timeout in seconds.
100
+ #
101
+ # Returns the last updated time for the table
102
+ def get_table(table_name, options={})
103
+ query = { }
104
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
105
+
106
+ response = call(:get, table_uri(table_name, query))
107
+ results = Azure::Storage::Table::Serialization.hash_from_entry_xml(response.body)
108
+ results[:updated]
109
+ end
110
+
111
+ # Public: Gets a list of all tables on the account.
112
+ #
113
+ # ==== Attributes
114
+ #
115
+ # * +options+ - Hash. Optional parameters.
116
+ #
117
+ # ==== Options
118
+ #
119
+ # Accepted key/value pairs in options parameter are:
120
+ # * +:next_table_token+ - String. A token used to enumerate the next page of results, when the list of tables is
121
+ # larger than a single operation can return at once. (optional)
122
+ # * +:timeout+ - Integer. A timeout in seconds.
123
+ #
124
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179405
125
+ #
126
+ # Returns an array with an extra continuation_token property on success
127
+ def query_tables(options={})
128
+ query = { }
129
+ query["NextTableName"] = options[:next_table_token] if options[:next_table_token]
130
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
131
+ uri = collection_uri(query)
132
+
133
+ response = call(:get, uri)
134
+ entries = Azure::Storage::Table::Serialization.entries_from_feed_xml(response.body) || []
135
+
136
+ values = Azure::Service::EnumerationResults.new(entries)
137
+ values.continuation_token = response.headers["x-ms-continuation-NextTableName"]
138
+ values
139
+ end
140
+
141
+ # Public: Gets the access control list (ACL) for the table.
142
+ #
143
+ # ==== Attributes
144
+ #
145
+ # * +table_name+ - String. The table name
146
+ # * +options+ - Hash. Optional parameters.
147
+ #
148
+ # ==== Options
149
+ #
150
+ # Accepted key/value pairs in options parameter are:
151
+ # * +:timeout+ - Integer. A timeout in seconds.
152
+ #
153
+ # See http://msdn.microsoft.com/en-us/library/azure/jj159100
154
+ #
155
+ # Returns a list of Azure::Storage::Entity::SignedIdentifier instances
156
+ def get_table_acl(table_name, options={})
157
+ query = { 'comp' => 'acl'}
158
+ query['timeout'] = options[:timeout].to_s if options[:timeout]
159
+
160
+ response = call(:get, generate_uri(table_name, query), nil, {'x-ms-version' => '2012-02-12'})
161
+
162
+ signed_identifiers = []
163
+ signed_identifiers = Azure::Storage::Table::Serialization.signed_identifiers_from_xml response.body unless response.body == nil or response.body.length < 1
164
+ signed_identifiers
165
+ end
166
+
167
+ # Public: Sets the access control list (ACL) for the table.
168
+ #
169
+ # ==== Attributes
170
+ #
171
+ # * +table_name+ - String. The table name
172
+ # * +options+ - Hash. Optional parameters.
173
+ #
174
+ # ==== Options
175
+ #
176
+ # Accepted key/value pairs in options parameter are:
177
+ # * +:signed_identifiers+ - Array. A list of Azure::Storage::Entity::SignedIdentifier instances
178
+ # * +:timeout+ - Integer. A timeout in seconds.
179
+ #
180
+ # See http://msdn.microsoft.com/en-us/library/azure/jj159102
181
+ #
182
+ # Returns nil on success
183
+ def set_table_acl(table_name, options={})
184
+ query = { 'comp' => 'acl'}
185
+ query['timeout'] = options[:timeout].to_s if options[:timeout]
186
+
187
+ uri = generate_uri(table_name, query)
188
+ body = nil
189
+ body = Azure::Storage::Table::Serialization.signed_identifiers_to_xml options[:signed_identifiers] if options[:signed_identifiers] && options[:signed_identifiers].length > 0
190
+
191
+ call(:put, uri, body, {'x-ms-version' => '2012-02-12'})
192
+ nil
193
+ end
194
+
195
+ # Public: Inserts new entity to the table.
196
+ #
197
+ #
198
+ # ==== Attributes
199
+ #
200
+ # * +table_name+ - String. The table name
201
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
202
+ # * +options+ - Hash. Optional parameters.
203
+ #
204
+ # ==== Options
205
+ #
206
+ # Accepted key/value pairs in options parameter are:
207
+ # * +:timeout+ - Integer. A timeout in seconds.
208
+ #
209
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179433
210
+ #
211
+ # Returns a Azure::Storage::Entity::Table::Entity
212
+ def insert_entity(table_name, entity_values, options={})
213
+ body = Azure::Storage::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
214
+
215
+ query = { }
216
+ query['timeout'] = options[:timeout].to_s if options[:timeout]
217
+
218
+ response = call(:post, entities_uri(table_name, nil, nil, query), body)
219
+
220
+ result = Azure::Storage::Table::Serialization.hash_from_entry_xml(response.body)
221
+
222
+ Entity.new do |entity|
223
+ entity.table = table_name
224
+ entity.updated = result[:updated]
225
+ entity.etag = response.headers['etag'] || result[:etag]
226
+ entity.properties = result[:properties]
227
+ end
228
+ end
229
+
230
+ # Public: Queries entities for the given table name
231
+ #
232
+ # ==== Attributes
233
+ #
234
+ # * +table_name+ - String. The table name
235
+ # * +options+ - Hash. Optional parameters.
236
+ #
237
+ # ==== Options
238
+ #
239
+ # Accepted key/value pairs in options parameter are:
240
+ # * +:partition_key+ - String. The partition key (optional)
241
+ # * +:row_key+ - String. The row key (optional)
242
+ # * +:select+ - Array. An array of property names to return (optional)
243
+ # * +:filter+ - String. A filter expression (optional)
244
+ # * +:top+ - Integer. A limit for the number of results returned (optional)
245
+ # * +:continuation_token+ - Hash. The continuation token.
246
+ # * +:timeout+ - Integer. A timeout in seconds.
247
+ #
248
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179421
249
+ #
250
+ # Returns an array with an extra continuation_token property on success
251
+ def query_entities(table_name, options={})
252
+ query ={}
253
+ query["$select"] = options[:select].join ',' if options[:select]
254
+ query["$filter"] = options[:filter] if options[:filter]
255
+ query["$top"] = options[:top].to_s if options[:top] unless options[:partition_key] and options[:row_key]
256
+ query["NextPartitionKey"] = options[:continuation_token][:next_partition_key] if options[:continuation_token] and options[:continuation_token][:next_partition_key]
257
+ query["NextRowKey"] = options[:continuation_token][:next_row_key] if options[:continuation_token] and options[:continuation_token][:next_row_key]
258
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
259
+
260
+ uri = entities_uri(table_name, options[:partition_key], options[:row_key], query)
261
+ response = call(:get, uri, nil, { "DataServiceVersion" => "2.0;NetFx"})
262
+
263
+ entities = Azure::Service::EnumerationResults.new
264
+
265
+ results = (options[:partition_key] and options[:row_key]) ? [Azure::Storage::Table::Serialization.hash_from_entry_xml(response.body)] : Azure::Storage::Table::Serialization.entries_from_feed_xml(response.body)
266
+
267
+ results.each do |result|
268
+ entity = Entity.new do |e|
269
+ e.table = table_name
270
+ e.updated = result[:updated]
271
+ e.etag = response.headers["etag"] || result[:etag]
272
+ e.properties = result[:properties]
273
+ end
274
+ entities.push entity
275
+ end if results
276
+
277
+ entities.continuation_token = nil
278
+ entities.continuation_token = {
279
+ :next_partition_key=> response.headers["x-ms-continuation-NextPartitionKey"],
280
+ :next_row_key => response.headers["x-ms-continuation-NextRowKey"]
281
+ } if response.headers["x-ms-continuation-NextPartitionKey"]
282
+
283
+ entities
284
+ end
285
+
286
+ # Public: Updates an existing entity in a table. The Update Entity operation replaces
287
+ # the entire entity and can be used to remove properties.
288
+ #
289
+ # ==== Attributes
290
+ #
291
+ # * +table_name+ - String. The table name
292
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
293
+ # * +options+ - Hash. Optional parameters.
294
+ #
295
+ # ==== Options
296
+ #
297
+ # Accepted key/value pairs in options parameter are:
298
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
299
+ # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
300
+ # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
301
+ # * +:timeout+ - Integer. A timeout in seconds.
302
+ #
303
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179427
304
+ #
305
+ # Returns the ETag for the entity on success
306
+ def update_entity(table_name, entity_values, options={})
307
+ if_match = "*"
308
+ if_match = options[:if_match] if options[:if_match]
309
+
310
+ query = { }
311
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
312
+
313
+ uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
314
+
315
+ headers = {}
316
+ headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
317
+
318
+ body = Azure::Storage::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
319
+
320
+ response = call(:put, uri, body, headers)
321
+ response.headers["etag"]
322
+ end
323
+
324
+ # Public: Updates an existing entity by updating the entity's properties. This operation
325
+ # does not replace the existing entity, as the update_entity operation does.
326
+ #
327
+ # ==== Attributes
328
+ #
329
+ # * +table_name+ - String. The table name
330
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
331
+ # * +options+ - Hash. Optional parameters.
332
+ #
333
+ # ==== Options
334
+ #
335
+ # Accepted key/value pairs in options parameter are:
336
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
337
+ # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
338
+ # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
339
+ # * +:timeout+ - Integer. A timeout in seconds.
340
+ #
341
+ # See http://msdn.microsoft.com/en-us/library/azure/dd179392
342
+ #
343
+ # Returns the ETag for the entity on success
344
+ def merge_entity(table_name, entity_values, options={})
345
+ if_match = "*"
346
+ if_match = options[:if_match] if options[:if_match]
347
+
348
+ query = { }
349
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
350
+
351
+ uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
352
+
353
+ headers = { "X-HTTP-Method"=> "MERGE" }
354
+ headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
355
+
356
+ body = Azure::Storage::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
357
+
358
+ response = call(:post, uri, body, headers)
359
+ response.headers["etag"]
360
+ end
361
+
362
+ # Public: Inserts or updates an existing entity within a table by merging new property values into the entity.
363
+ #
364
+ # ==== Attributes
365
+ #
366
+ # * +table_name+ - String. The table name
367
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
368
+ # * +options+ - Hash. Optional parameters.
369
+ #
370
+ # ==== Options
371
+ #
372
+ # Accepted key/value pairs in options parameter are:
373
+ # * +:timeout+ - Integer. A timeout in seconds.
374
+ #
375
+ # See http://msdn.microsoft.com/en-us/library/azure/hh452241
376
+ #
377
+ # Returns the ETag for the entity on success
378
+ def insert_or_merge_entity(table_name, entity_values, options={})
379
+ options[:create_if_not_exists] = true
380
+ merge_entity(table_name, entity_values, options)
381
+ end
382
+
383
+ # Public: Inserts or updates a new entity into a table.
384
+ #
385
+ # ==== Attributes
386
+ #
387
+ # * +table_name+ - String. The table name
388
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
389
+ # * +options+ - Hash. Optional parameters.
390
+ #
391
+ # ==== Options
392
+ #
393
+ # Accepted key/value pairs in options parameter are:
394
+ # * +:timeout+ - Integer. A timeout in seconds.
395
+ #
396
+ # See http://msdn.microsoft.com/en-us/library/azure/hh452242
397
+ #
398
+ # Returns the ETag for the entity on success
399
+ def insert_or_replace_entity(table_name, entity_values, options={})
400
+ options[:create_if_not_exists] = true
401
+ update_entity(table_name, entity_values, options)
402
+ end
403
+
404
+ # Public: Deletes an existing entity in the table.
405
+ #
406
+ # ==== Attributes
407
+ #
408
+ # * +table_name+ - String. The table name
409
+ # * +partition_key+ - String. The partition key
410
+ # * +row_key+ - String. The row key
411
+ # * +options+ - Hash. Optional parameters.
412
+ #
413
+ # ==== Options
414
+ #
415
+ # Accepted key/value pairs in options parameter are:
416
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
417
+ # * +:timeout+ - Integer. A timeout in seconds.
418
+ #
419
+ # See http://msdn.microsoft.com/en-us/library/azure/dd135727
420
+ #
421
+ # Returns nil on success
422
+ def delete_entity(table_name, partition_key, row_key, options={})
423
+ if_match = "*"
424
+ if_match = options[:if_match] if options[:if_match]
425
+
426
+ query = { }
427
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
428
+
429
+ call(:delete, entities_uri(table_name, partition_key, row_key, query), nil, { "If-Match"=> if_match })
430
+ nil
431
+ end
432
+
433
+ # Public: Executes a batch of operations.
434
+ #
435
+ # ==== Attributes
436
+ #
437
+ # * +batch+ - The Azure::Storage::Table::Batch instance to execute.
438
+ # * +options+ - Hash. Optional parameters.
439
+ #
440
+ # ==== Options
441
+ #
442
+ # Accepted key/value pairs in options parameter are:
443
+ # * +:timeout+ - Integer. A timeout in seconds.
444
+ #
445
+ # See http://msdn.microsoft.com/en-us/library/azure/dd894038
446
+ #
447
+ # Returns an array of results, one for each operation in the batch
448
+ def execute_batch(batch, options={})
449
+ headers = {
450
+ 'Content-Type' => "multipart/mixed; boundary=#{batch.batch_id}",
451
+ 'Accept' => 'application/atom+xml,application/xml',
452
+ 'Accept-Charset'=> 'UTF-8'
453
+ }
454
+
455
+ query = { }
456
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
457
+
458
+ body = batch.to_body
459
+ response = call(:post, generate_uri('/$batch', query), body, headers)
460
+ batch.parse_response(response)
461
+ end
462
+
463
+ # Public: Gets an existing entity in the table.
464
+ #
465
+ # ==== Attributes
466
+ #
467
+ # * +table_name+ - String. The table name
468
+ # * +partition_key+ - String. The partition key
469
+ # * +row_key+ - String. The row key
470
+ # * +options+ - Hash. Optional parameters.
471
+ #
472
+ # ==== Options
473
+ #
474
+ # Accepted key/value pairs in options parameter are:
475
+ # * +:timeout+ - Integer. A timeout in seconds.
476
+ #
477
+ # Returns an Azure::Storage::Table::Entity instance on success
478
+ def get_entity(table_name, partition_key, row_key, options={})
479
+ options[:partition_key] = partition_key
480
+ options[:row_key] = row_key
481
+ results = query_entities(table_name, options)
482
+ results.length > 0 ? results[0] : nil
483
+ end
484
+
485
+ # Protected: Generate the URI for the collection of tables.
486
+ #
487
+ # Returns a URI
488
+ protected
489
+ def collection_uri(query={})
490
+ generate_uri("Tables", query)
491
+ end
492
+
493
+ # Public: Generate the URI for a specific table.
494
+ #
495
+ # ==== Attributes
496
+ #
497
+ # * +name+ - The table name. If this is a URI, we just return this
498
+ #
499
+ # Returns a URI
500
+ public
501
+ def table_uri(name, query={})
502
+ return name if name.kind_of? ::URI
503
+ generate_uri("Tables('#{name}')", query)
504
+ end
505
+
506
+ # Public: Generate the URI for an entity or group of entities in a table.
507
+ # If both the 'partition_key' and 'row_key' are specified, then the URI
508
+ # will match the entity under those specific keys.
509
+ #
510
+ # ==== Attributes
511
+ #
512
+ # * +table_name+ - The table name
513
+ # * +partition_key+ - The desired partition key (optional)
514
+ # * +row_key+ - The desired row key (optional)
515
+ #
516
+ # Returns a URI
517
+ public
518
+ def entities_uri(table_name, partition_key=nil, row_key=nil, query={})
519
+ return table_name if table_name.kind_of? ::URI
520
+
521
+ path = if partition_key && row_key
522
+ "%s(PartitionKey='%s',RowKey='%s')" % [
523
+ table_name.encode("UTF-8"), encodeODataUriValue(partition_key.encode("UTF-8")), encodeODataUriValue(row_key.encode("UTF-8"))
524
+ ]
525
+ else
526
+ "%s()" % table_name.encode("UTF-8")
527
+ end
528
+
529
+ uri = generate_uri(path)
530
+ qs = []
531
+ if query
532
+ query.each do | key, val |
533
+ key = key.encode("UTF-8")
534
+ val = val.encode("UTF-8")
535
+
536
+ if key[0] == "$"
537
+ qs.push "#{key}#{::URI.encode_www_form(""=>val)}"
538
+ else
539
+ qs.push ::URI.encode_www_form(key=>val)
540
+ end
541
+ end
542
+ end
543
+ uri.query = qs.join '&' if qs.length > 0
544
+ uri
545
+ end
546
+
547
+ protected
548
+ def encodeODataUriValues(values)
549
+ new_values = []
550
+ values.each do |value|
551
+ new_values.push encodeODataUriValue(value)
552
+ end
553
+ new_values
554
+ end
555
+
556
+ protected
557
+ def encodeODataUriValue(value)
558
+ # Replace each single quote (') with double single quotes ('') not double
559
+ # quotes (")
560
+ value = value.gsub("'", "''")
561
+
562
+ # Encode the special URL characters
563
+ value = URI.escape(value)
564
+
565
+ value
566
+ end
567
+ end
568
+ end
569
+ end
570
+
571
+ Azure::Storage::TableService = Azure::Storage::Table::TableService