waz-storage 1.3.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +9 -9
  2. data/CHANGELOG.rdoc +72 -72
  3. data/Gemfile +4 -4
  4. data/Gemfile.lock +46 -46
  5. data/LICENSE +18 -18
  6. data/README.rdoc +310 -310
  7. data/lib/waz-blobs.rb +4 -4
  8. data/lib/waz-queues.rb +6 -6
  9. data/lib/waz-storage.rb +39 -39
  10. data/lib/waz-tables.rb +4 -4
  11. data/lib/waz/blobs/blob_object.rb +122 -122
  12. data/lib/waz/blobs/container.rb +172 -172
  13. data/lib/waz/blobs/exceptions.rb +10 -10
  14. data/lib/waz/blobs/service.rb +181 -181
  15. data/lib/waz/queues/exceptions.rb +28 -28
  16. data/lib/waz/queues/message.rb +64 -64
  17. data/lib/waz/queues/queue.rb +164 -164
  18. data/lib/waz/queues/service.rb +105 -105
  19. data/lib/waz/storage/base.rb +70 -70
  20. data/lib/waz/storage/core_service.rb +2 -1
  21. data/lib/waz/storage/exceptions.rb +33 -33
  22. data/lib/waz/storage/validation_rules.rb +25 -25
  23. data/lib/waz/tables/edm_type_helper.rb +44 -44
  24. data/lib/waz/tables/exceptions.rb +44 -44
  25. data/lib/waz/tables/service.rb +178 -178
  26. data/lib/waz/tables/table.rb +74 -74
  27. data/lib/waz/tables/table_array.rb +10 -10
  28. data/rakefile +7 -7
  29. data/spec/configuration.rb +22 -22
  30. data/spec/waz/blobs/blob_object_spec.rb +80 -80
  31. data/spec/waz/blobs/container_spec.rb +175 -175
  32. data/spec/waz/blobs/service_spec.rb +336 -336
  33. data/spec/waz/queues/message_spec.rb +32 -32
  34. data/spec/waz/queues/queue_spec.rb +205 -205
  35. data/spec/waz/queues/service_spec.rb +298 -298
  36. data/spec/waz/storage/base_tests.rb +81 -81
  37. data/spec/waz/storage/shared_key_core_service_spec.rb +141 -141
  38. data/spec/waz/tables/service_spec.rb +613 -613
  39. data/spec/waz/tables/table_spec.rb +97 -97
  40. data/waz-storage.gemspec +29 -29
  41. metadata +3 -3
@@ -1,178 +1,178 @@
1
- module WAZ
2
- module Tables
3
- # This is internally used by the waz-tables part of the gem and it exposes the Windows Azure Blob API REST methods
4
- # implementation. You can use this class to perform an specific operation that isn't provided by the current API.
5
- class Service
6
- include WAZ::Storage::SharedKeyCoreService
7
-
8
- DATASERVICES_NAMESPACE = "http://schemas.microsoft.com/ado/2007/08/dataservices"
9
- DATASERVICES_METADATA_NAMESPACE = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
10
-
11
- # Creates a table on the current Windows Azure Storage account.
12
- def create_table(table_name)
13
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
14
-
15
- payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
16
- "<entry xmlns:d=\"#{DATASERVICES_NAMESPACE}\" xmlns:m=\"#{DATASERVICES_METADATA_NAMESPACE}\" xmlns=\"http://www.w3.org/2005/Atom\">" \
17
- "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name/></author><id/>" \
18
- "<content type=\"application/xml\"><m:properties><d:TableName>#{table_name}</d:TableName></m:properties></content></entry>"
19
-
20
- begin
21
- execute :post, 'Tables', {}, default_headers, payload
22
- return {:name => table_name, :url => "#{self.base_url}/Tables('#{table_name}"}
23
- rescue RestClient::RequestFailed
24
- raise WAZ::Tables::TableAlreadyExists, table_name if $!.http_code == 409
25
- end
26
- end
27
-
28
- # Delete a table on the current Windows Azure Storage account.
29
- def delete_table(table_name)
30
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
31
- begin
32
- execute :delete, "Tables('#{table_name}')", {}, default_headers
33
- rescue RestClient::ResourceNotFound
34
- raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404
35
- end
36
- end
37
-
38
- # Lists all existing tables on the current storage account.
39
- # remove Content-Type if it's not working
40
- def list_tables(next_table_name = nil)
41
- query = { 'NextTableName' => next_table_name } unless next_table_name.nil?
42
- content = execute :get, "Tables", query ||= {}, default_headers
43
-
44
- doc = REXML::Document.new(content)
45
- tables = REXML::XPath.each(doc, '/feed/entry').map do |item|
46
- { :name => REXML::XPath.first(item.elements['content'], "m:properties/d:TableName", {"m" => DATASERVICES_METADATA_NAMESPACE, "d" => DATASERVICES_NAMESPACE}).text,
47
- :url => REXML::XPath.first(item, "id").text }
48
- end
49
-
50
- return tables, content.headers[:x_ms_continuation_nexttablename]
51
- end
52
-
53
- # Retrieves an existing table on the current storage account.
54
- # remove Content-Type if it's not working
55
- def get_table(table_name)
56
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
57
-
58
- begin
59
- content = execute :get, "Tables('#{table_name}')", {}, default_headers
60
- doc = REXML::Document.new(content)
61
- item = REXML::XPath.first(doc, "entry")
62
- return { :name => REXML::XPath.first(item.elements['content'], "m:properties/d:TableName", {"m" => DATASERVICES_METADATA_NAMESPACE, "d" => DATASERVICES_NAMESPACE}).text,
63
- :url => REXML::XPath.first(item, "id").text }
64
- rescue RestClient::ResourceNotFound
65
- raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404
66
- end
67
- end
68
-
69
- # Insert a new entity on the provided table for the current storage account
70
- # TODO: catch all api errors as described on Table Service Error Codes on MSDN (http://msdn.microsoft.com/en-us/library/dd179438.aspx)
71
- def insert_entity(table_name, entity)
72
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
73
- raise WAZ::Tables::TooManyProperties, entity.length if entity.length > 252
74
-
75
- begin
76
- response = execute(:post, table_name, {}, default_headers, generate_payload(table_name, entity))
77
- return parse_response(response)
78
- rescue RestClient::RequestFailed
79
- raise WAZ::Tables::EntityAlreadyExists, entity[:row_key] if $!.http_code == 409 and $!.response.body.include?('EntityAlreadyExists')
80
- end
81
- end
82
-
83
- # Update an existing entity on the current storage account.
84
- # TODO: handle specific errors
85
- def update_entity(table_name, entity)
86
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
87
- response = execute(:put, "#{table_name}(PartitionKey='#{entity[:partition_key]}',RowKey='#{entity[:row_key]}')", {}, default_headers.merge({'If-Match' => '*'}) , generate_payload(table_name, entity))
88
- return parse_response(response)
89
- end
90
-
91
- # Merge an existing entity on the current storage account.
92
- # The Merge Entity operation updates an existing entity by updating the entity's properties.
93
- # This operation does not replace the existing entity, as the Update Entity operation does
94
- # TODO: handle specific errors
95
- def merge_entity(table_name, entity)
96
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
97
- response = execute(:merge, "#{table_name}(PartitionKey='#{entity[:partition_key]}',RowKey='#{entity[:row_key]}')", {}, default_headers.merge({'If-Match' => '*'}), generate_payload(table_name, entity))
98
- return parse_response(response)
99
- end
100
-
101
- # Delete an existing entity in a table.
102
- def delete_entity(table_name, partition_key, row_key)
103
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
104
-
105
- begin
106
- execute :delete, "#{table_name}(PartitionKey='#{partition_key}',RowKey='#{row_key}')", {}, default_headers.merge({'If-Match' => '*'})
107
- rescue RestClient::ResourceNotFound
108
- raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404 and $!.response.body.include?('TableNotFound')
109
- raise WAZ::Tables::EntityDoesNotExist, "(PartitionKey='#{partition_key}',RowKey='#{row_key}')" if $!.http_code == 404
110
- end
111
- end
112
-
113
- # Retrieves an existing entity on the current storage account.
114
- # TODO: handle specific errors
115
- def get_entity(table_name, partition_key, row_key)
116
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
117
- response = execute(:get, "#{table_name}(PartitionKey='#{partition_key}',RowKey='#{row_key}')", {}, default_headers)
118
- return parse_response(response)
119
- end
120
-
121
- # Retrieves a set of entities on the current storage account for a given query.
122
- # When the :top => n is passed it returns only the first n rows that match with the query
123
- # Optional parameters:
124
- # * :headers a hash containing the request headers
125
- # * :expression the filter query that will be executed against the table (see http://msdn.microsoft.com/en-us/library/dd179421.aspx for more information),
126
- # * :top limits the amount of fields for this query.
127
- # * :continuation_token the hash obtained when you perform a query that has more than 1000 records or exceeds the allowed timeout (see http://msdn.microsoft.com/en-us/library/dd135718.aspx)
128
- def query(table_name, options = {})
129
- raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
130
- query = {'$filter' => (options[:expression] or '') }
131
- query.merge!({ '$top' => options[:top] }) unless options[:top].nil?
132
- query.merge!(options[:continuation_token]) unless options[:continuation_token].nil?
133
- response = execute :get, "#{table_name}()", query, default_headers
134
- continuation_token = {'NextPartitionKey' => response.headers[:x_ms_continuation_nextpartitionkey], 'NextRowKey' => response.headers[:x_ms_continuation_nextrowkey]}
135
- parse_response(response, continuation_token)
136
- end
137
-
138
- private
139
- def generate_payload(table_name, entity)
140
- payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
141
- "<entry xmlns:d=\"#{DATASERVICES_NAMESPACE}\" xmlns:m=\"#{DATASERVICES_METADATA_NAMESPACE}\" xmlns=\"http://www.w3.org/2005/Atom\">" \
142
- "<id>#{generate_request_uri "#{table_name}"}(PartitionKey='#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}',RowKey='#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}')</id>" \
143
- "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name /></author><link rel=\"edit\" title=\"#{table_name}\" href=\"#{table_name}(PartitionKey='#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}',RowKey='#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}')\" />" \
144
- "<content type=\"application/xml\"><m:properties>"
145
-
146
- entity.sort_by { |k| k.to_s }.each do |k,v|
147
- value, type = EdmTypeHelper.parse_to(v)[0].to_s, EdmTypeHelper.parse_to(v)[1].to_s
148
- payload << (!v.nil? ? "<d:#{k.to_s} m:type=\"#{k.edm_type || type}\">#{REXML::Text.new(value, false, nil, false).to_s}</d:#{k.to_s}>" : "<d:#{k.to_s} m:type=\"#{k.edm_type || type}\" m:null=\"true\" />") unless k.eql?(:partition_key) or k.eql?(:row_key)
149
- end
150
-
151
- payload << "<d:PartitionKey>#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}</d:PartitionKey>" \
152
- "<d:RowKey>#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}</d:RowKey>" \
153
- "</m:properties></content></entry>"
154
- return payload
155
- end
156
-
157
- def parse_response(response, continuation_token = nil)
158
- doc = REXML::Document.new(response)
159
- entities = REXML::XPath.each(doc, '//entry').map do |entry|
160
- fields = REXML::XPath.each(entry.elements['content'], 'm:properties/*', {"m" => DATASERVICES_METADATA_NAMESPACE}).map do |f|
161
- { f.name.gsub(/PartitionKey/i, 'partition_key').gsub(/RowKey/i, 'row_key').to_sym => EdmTypeHelper.parse_from(f) }
162
- end
163
- Hash[*fields.collect {|h| h.to_a}.flatten]
164
- end
165
- entities = WAZ::Tables::TableArray.new(entities)
166
- entities.continuation_token = continuation_token
167
- return (REXML::XPath.first(doc, '/feed')) ? entities : entities.first
168
- end
169
-
170
- def default_headers
171
- { 'Date' => Time.new.httpdate,
172
- 'Content-Type' => 'application/atom+xml',
173
- 'DataServiceVersion' => '1.0;NetFx',
174
- 'MaxDataServiceVersion' => '1.0;NetFx' }
175
- end
176
- end
177
- end
178
- end
1
+ module WAZ
2
+ module Tables
3
+ # This is internally used by the waz-tables part of the gem and it exposes the Windows Azure Blob API REST methods
4
+ # implementation. You can use this class to perform an specific operation that isn't provided by the current API.
5
+ class Service
6
+ include WAZ::Storage::SharedKeyCoreService
7
+
8
+ DATASERVICES_NAMESPACE = "http://schemas.microsoft.com/ado/2007/08/dataservices"
9
+ DATASERVICES_METADATA_NAMESPACE = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
10
+
11
+ # Creates a table on the current Windows Azure Storage account.
12
+ def create_table(table_name)
13
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
14
+
15
+ payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
16
+ "<entry xmlns:d=\"#{DATASERVICES_NAMESPACE}\" xmlns:m=\"#{DATASERVICES_METADATA_NAMESPACE}\" xmlns=\"http://www.w3.org/2005/Atom\">" \
17
+ "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name/></author><id/>" \
18
+ "<content type=\"application/xml\"><m:properties><d:TableName>#{table_name}</d:TableName></m:properties></content></entry>"
19
+
20
+ begin
21
+ execute :post, 'Tables', {}, default_headers, payload
22
+ return {:name => table_name, :url => "#{self.base_url}/Tables('#{table_name}"}
23
+ rescue RestClient::RequestFailed
24
+ raise WAZ::Tables::TableAlreadyExists, table_name if $!.http_code == 409
25
+ end
26
+ end
27
+
28
+ # Delete a table on the current Windows Azure Storage account.
29
+ def delete_table(table_name)
30
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
31
+ begin
32
+ execute :delete, "Tables('#{table_name}')", {}, default_headers
33
+ rescue RestClient::ResourceNotFound
34
+ raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404
35
+ end
36
+ end
37
+
38
+ # Lists all existing tables on the current storage account.
39
+ # remove Content-Type if it's not working
40
+ def list_tables(next_table_name = nil)
41
+ query = { 'NextTableName' => next_table_name } unless next_table_name.nil?
42
+ content = execute :get, "Tables", query ||= {}, default_headers
43
+
44
+ doc = REXML::Document.new(content)
45
+ tables = REXML::XPath.each(doc, '/feed/entry').map do |item|
46
+ { :name => REXML::XPath.first(item.elements['content'], "m:properties/d:TableName", {"m" => DATASERVICES_METADATA_NAMESPACE, "d" => DATASERVICES_NAMESPACE}).text,
47
+ :url => REXML::XPath.first(item, "id").text }
48
+ end
49
+
50
+ return tables, content.headers[:x_ms_continuation_nexttablename]
51
+ end
52
+
53
+ # Retrieves an existing table on the current storage account.
54
+ # remove Content-Type if it's not working
55
+ def get_table(table_name)
56
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
57
+
58
+ begin
59
+ content = execute :get, "Tables('#{table_name}')", {}, default_headers
60
+ doc = REXML::Document.new(content)
61
+ item = REXML::XPath.first(doc, "entry")
62
+ return { :name => REXML::XPath.first(item.elements['content'], "m:properties/d:TableName", {"m" => DATASERVICES_METADATA_NAMESPACE, "d" => DATASERVICES_NAMESPACE}).text,
63
+ :url => REXML::XPath.first(item, "id").text }
64
+ rescue RestClient::ResourceNotFound
65
+ raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404
66
+ end
67
+ end
68
+
69
+ # Insert a new entity on the provided table for the current storage account
70
+ # TODO: catch all api errors as described on Table Service Error Codes on MSDN (http://msdn.microsoft.com/en-us/library/dd179438.aspx)
71
+ def insert_entity(table_name, entity)
72
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
73
+ raise WAZ::Tables::TooManyProperties, entity.length if entity.length > 252
74
+
75
+ begin
76
+ response = execute(:post, table_name, {}, default_headers, generate_payload(table_name, entity))
77
+ return parse_response(response)
78
+ rescue RestClient::RequestFailed
79
+ raise WAZ::Tables::EntityAlreadyExists, entity[:row_key] if $!.http_code == 409 and $!.response.body.include?('EntityAlreadyExists')
80
+ end
81
+ end
82
+
83
+ # Update an existing entity on the current storage account.
84
+ # TODO: handle specific errors
85
+ def update_entity(table_name, entity)
86
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
87
+ response = execute(:put, "#{table_name}(PartitionKey='#{entity[:partition_key]}',RowKey='#{entity[:row_key]}')", {}, default_headers.merge({'If-Match' => '*'}) , generate_payload(table_name, entity))
88
+ return parse_response(response)
89
+ end
90
+
91
+ # Merge an existing entity on the current storage account.
92
+ # The Merge Entity operation updates an existing entity by updating the entity's properties.
93
+ # This operation does not replace the existing entity, as the Update Entity operation does
94
+ # TODO: handle specific errors
95
+ def merge_entity(table_name, entity)
96
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
97
+ response = execute(:merge, "#{table_name}(PartitionKey='#{entity[:partition_key]}',RowKey='#{entity[:row_key]}')", {}, default_headers.merge({'If-Match' => '*'}), generate_payload(table_name, entity))
98
+ return parse_response(response)
99
+ end
100
+
101
+ # Delete an existing entity in a table.
102
+ def delete_entity(table_name, partition_key, row_key)
103
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
104
+
105
+ begin
106
+ execute :delete, "#{table_name}(PartitionKey='#{partition_key}',RowKey='#{row_key}')", {}, default_headers.merge({'If-Match' => '*'})
107
+ rescue RestClient::ResourceNotFound
108
+ raise WAZ::Tables::TableDoesNotExist, table_name if $!.http_code == 404 and $!.response.body.include?('TableNotFound')
109
+ raise WAZ::Tables::EntityDoesNotExist, "(PartitionKey='#{partition_key}',RowKey='#{row_key}')" if $!.http_code == 404
110
+ end
111
+ end
112
+
113
+ # Retrieves an existing entity on the current storage account.
114
+ # TODO: handle specific errors
115
+ def get_entity(table_name, partition_key, row_key)
116
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
117
+ response = execute(:get, "#{table_name}(PartitionKey='#{partition_key}',RowKey='#{row_key}')", {}, default_headers)
118
+ return parse_response(response)
119
+ end
120
+
121
+ # Retrieves a set of entities on the current storage account for a given query.
122
+ # When the :top => n is passed it returns only the first n rows that match with the query
123
+ # Optional parameters:
124
+ # * :headers a hash containing the request headers
125
+ # * :expression the filter query that will be executed against the table (see http://msdn.microsoft.com/en-us/library/dd179421.aspx for more information),
126
+ # * :top limits the amount of fields for this query.
127
+ # * :continuation_token the hash obtained when you perform a query that has more than 1000 records or exceeds the allowed timeout (see http://msdn.microsoft.com/en-us/library/dd135718.aspx)
128
+ def query(table_name, options = {})
129
+ raise WAZ::Tables::InvalidTableName, table_name unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
130
+ query = {'$filter' => (options[:expression] or '') }
131
+ query.merge!({ '$top' => options[:top] }) unless options[:top].nil?
132
+ query.merge!(options[:continuation_token]) unless options[:continuation_token].nil?
133
+ response = execute :get, "#{table_name}()", query, default_headers
134
+ continuation_token = {'NextPartitionKey' => response.headers[:x_ms_continuation_nextpartitionkey], 'NextRowKey' => response.headers[:x_ms_continuation_nextrowkey]}
135
+ parse_response(response, continuation_token)
136
+ end
137
+
138
+ private
139
+ def generate_payload(table_name, entity)
140
+ payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
141
+ "<entry xmlns:d=\"#{DATASERVICES_NAMESPACE}\" xmlns:m=\"#{DATASERVICES_METADATA_NAMESPACE}\" xmlns=\"http://www.w3.org/2005/Atom\">" \
142
+ "<id>#{generate_request_uri "#{table_name}"}(PartitionKey='#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}',RowKey='#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}')</id>" \
143
+ "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name /></author><link rel=\"edit\" title=\"#{table_name}\" href=\"#{table_name}(PartitionKey='#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}',RowKey='#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}')\" />" \
144
+ "<content type=\"application/xml\"><m:properties>"
145
+
146
+ entity.sort_by { |k| k.to_s }.each do |k,v|
147
+ value, type = EdmTypeHelper.parse_to(v)[0].to_s, EdmTypeHelper.parse_to(v)[1].to_s
148
+ payload << (!v.nil? ? "<d:#{k.to_s} m:type=\"#{k.edm_type || type}\">#{REXML::Text.new(value, false, nil, false).to_s}</d:#{k.to_s}>" : "<d:#{k.to_s} m:type=\"#{k.edm_type || type}\" m:null=\"true\" />") unless k.eql?(:partition_key) or k.eql?(:row_key)
149
+ end
150
+
151
+ payload << "<d:PartitionKey>#{REXML::Text.new(entity[:partition_key], false, nil, false).to_s}</d:PartitionKey>" \
152
+ "<d:RowKey>#{REXML::Text.new(entity[:row_key], false, nil, false).to_s}</d:RowKey>" \
153
+ "</m:properties></content></entry>"
154
+ return payload
155
+ end
156
+
157
+ def parse_response(response, continuation_token = nil)
158
+ doc = REXML::Document.new(response)
159
+ entities = REXML::XPath.each(doc, '//entry').map do |entry|
160
+ fields = REXML::XPath.each(entry.elements['content'], 'm:properties/*', {"m" => DATASERVICES_METADATA_NAMESPACE}).map do |f|
161
+ { f.name.gsub(/PartitionKey/i, 'partition_key').gsub(/RowKey/i, 'row_key').to_sym => EdmTypeHelper.parse_from(f) }
162
+ end
163
+ Hash[*fields.collect {|h| h.to_a}.flatten]
164
+ end
165
+ entities = WAZ::Tables::TableArray.new(entities)
166
+ entities.continuation_token = continuation_token
167
+ return (REXML::XPath.first(doc, '/feed')) ? entities : entities.first
168
+ end
169
+
170
+ def default_headers
171
+ { 'Date' => Time.new.httpdate,
172
+ 'Content-Type' => 'application/atom+xml',
173
+ 'DataServiceVersion' => '1.0;NetFx',
174
+ 'MaxDataServiceVersion' => '1.0;NetFx' }
175
+ end
176
+ end
177
+ end
178
+ end
@@ -1,75 +1,75 @@
1
- module WAZ
2
- module Tables
3
- # This class represents a Table on Windows Azure Tables API. These are the methods implemented from Microsoft's API description
4
- # available on MSDN at http://msdn.microsoft.com/en-us/library/dd179423.aspx
5
- #
6
- # # list available tables
7
- # tables = WAZ::Tables::Table.list
8
- #
9
- # # list more tables
10
- # WAZ::Tables::Table.list(tables.continuation_token)
11
- #
12
- # # get a specific table
13
- # my_table = WAZ::Tables::Table.find('my-table')
14
- #
15
- # # delete table
16
- # my_table.destroy!
17
- #
18
- # # create a new table
19
- # WAZ::Tables::Table.create('new-table')
20
- #
21
- class Table
22
- class << self
23
- INVALID_TABLE_ERROR_MESSAGE = "must start with at least one lower/upper characted, can have character or any digit starting from the second position, must be from 3 through 63 characters long"
24
-
25
- # Finds a table by name. It will return nil if no table was found.
26
- def find(table_name)
27
- raise WAZ::Storage::InvalidParameterValue, {:name => table_name, :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
28
- begin
29
- WAZ::Tables::Table.new(service_instance.get_table(table_name))
30
- rescue WAZ::Tables::TableDoesNotExist
31
- return nil
32
- end
33
- end
34
-
35
- # Returns an array of the existing tables (WAZ::Tables::Table) on the current
36
- # Windows Azure Storage account.
37
- def list(continuation_token = {})
38
- table_list, next_table_name = service_instance.list_tables(continuation_token['NextTableName'])
39
- tables = TableArray.new(table_list.map { |table| WAZ::Tables::Table.new({ :name => table[:name], :url => table[:url] }) })
40
- tables.continuation_token = {'NextTableName' => next_table_name} unless next_table_name.nil?
41
- return tables
42
- end
43
-
44
- # Creates a table on the current account.
45
- def create(table_name)
46
- raise WAZ::Storage::InvalidParameterValue, {:name => table_name, :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
47
- WAZ::Tables::Table.new(service_instance.create_table(table_name))
48
- end
49
-
50
- # This method is internally used by this class. It's the way we keep a single instance of the
51
- # service that wraps the calls the Windows Azure Tables API. It's initialized with the values
52
- # from the default_connection on WAZ::Storage::Base initialized thru establish_connection!
53
- def service_instance
54
- options = WAZ::Storage::Base.default_connection.merge(:type_of_service => "table")
55
- (@service_instances ||= {})[options[:account_name]] ||= Service.new(options)
56
- end
57
- end
58
-
59
- attr_accessor :name, :url
60
-
61
- def initialize(options = {})
62
- raise WAZ::Storage::InvalidOption, :name unless options.keys.include?(:name) and !options[:name].empty?
63
- raise WAZ::Storage::InvalidOption, :url unless options.keys.include?(:url) and !options[:url].empty?
64
- raise WAZ::Storage::InvalidParameterValue, {:name => options[:name], :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(options[:name])
65
- self.name = options[:name]
66
- self.url = options[:url]
67
- end
68
-
69
- # Removes the table from the current account.
70
- def destroy!
71
- self.class.service_instance.delete_table(self.name)
72
- end
73
- end
74
- end
1
+ module WAZ
2
+ module Tables
3
+ # This class represents a Table on Windows Azure Tables API. These are the methods implemented from Microsoft's API description
4
+ # available on MSDN at http://msdn.microsoft.com/en-us/library/dd179423.aspx
5
+ #
6
+ # # list available tables
7
+ # tables = WAZ::Tables::Table.list
8
+ #
9
+ # # list more tables
10
+ # WAZ::Tables::Table.list(tables.continuation_token)
11
+ #
12
+ # # get a specific table
13
+ # my_table = WAZ::Tables::Table.find('my-table')
14
+ #
15
+ # # delete table
16
+ # my_table.destroy!
17
+ #
18
+ # # create a new table
19
+ # WAZ::Tables::Table.create('new-table')
20
+ #
21
+ class Table
22
+ class << self
23
+ INVALID_TABLE_ERROR_MESSAGE = "must start with at least one lower/upper characted, can have character or any digit starting from the second position, must be from 3 through 63 characters long"
24
+
25
+ # Finds a table by name. It will return nil if no table was found.
26
+ def find(table_name)
27
+ raise WAZ::Storage::InvalidParameterValue, {:name => table_name, :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
28
+ begin
29
+ WAZ::Tables::Table.new(service_instance.get_table(table_name))
30
+ rescue WAZ::Tables::TableDoesNotExist
31
+ return nil
32
+ end
33
+ end
34
+
35
+ # Returns an array of the existing tables (WAZ::Tables::Table) on the current
36
+ # Windows Azure Storage account.
37
+ def list(continuation_token = {})
38
+ table_list, next_table_name = service_instance.list_tables(continuation_token['NextTableName'])
39
+ tables = TableArray.new(table_list.map { |table| WAZ::Tables::Table.new({ :name => table[:name], :url => table[:url] }) })
40
+ tables.continuation_token = {'NextTableName' => next_table_name} unless next_table_name.nil?
41
+ return tables
42
+ end
43
+
44
+ # Creates a table on the current account.
45
+ def create(table_name)
46
+ raise WAZ::Storage::InvalidParameterValue, {:name => table_name, :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(table_name)
47
+ WAZ::Tables::Table.new(service_instance.create_table(table_name))
48
+ end
49
+
50
+ # This method is internally used by this class. It's the way we keep a single instance of the
51
+ # service that wraps the calls the Windows Azure Tables API. It's initialized with the values
52
+ # from the default_connection on WAZ::Storage::Base initialized thru establish_connection!
53
+ def service_instance
54
+ options = WAZ::Storage::Base.default_connection.merge(:type_of_service => "table")
55
+ (@service_instances ||= {})[options[:account_name]] ||= Service.new(options)
56
+ end
57
+ end
58
+
59
+ attr_accessor :name, :url
60
+
61
+ def initialize(options = {})
62
+ raise WAZ::Storage::InvalidOption, :name unless options.keys.include?(:name) and !options[:name].empty?
63
+ raise WAZ::Storage::InvalidOption, :url unless options.keys.include?(:url) and !options[:url].empty?
64
+ raise WAZ::Storage::InvalidParameterValue, {:name => options[:name], :values => [INVALID_TABLE_ERROR_MESSAGE]} unless WAZ::Storage::ValidationRules.valid_table_name?(options[:name])
65
+ self.name = options[:name]
66
+ self.url = options[:url]
67
+ end
68
+
69
+ # Removes the table from the current account.
70
+ def destroy!
71
+ self.class.service_instance.delete_table(self.name)
72
+ end
73
+ end
74
+ end
75
75
  end