sparqcode-waz-storage 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/CHANGELOG.rdoc +72 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +19 -0
- data/README.rdoc +299 -0
- data/lib/waz-blobs.rb +5 -0
- data/lib/waz-queues.rb +6 -0
- data/lib/waz-storage.rb +39 -0
- data/lib/waz-tables.rb +5 -0
- data/lib/waz/blobs/blob_object.rb +121 -0
- data/lib/waz/blobs/container.rb +160 -0
- data/lib/waz/blobs/exceptions.rb +11 -0
- data/lib/waz/blobs/service.rb +156 -0
- data/lib/waz/queues/exceptions.rb +29 -0
- data/lib/waz/queues/message.rb +65 -0
- data/lib/waz/queues/queue.rb +165 -0
- data/lib/waz/queues/service.rb +106 -0
- data/lib/waz/storage/base.rb +70 -0
- data/lib/waz/storage/core_service.rb +122 -0
- data/lib/waz/storage/exceptions.rb +33 -0
- data/lib/waz/storage/validation_rules.rb +26 -0
- data/lib/waz/storage/version.rb +11 -0
- data/lib/waz/tables/edm_type_helper.rb +45 -0
- data/lib/waz/tables/exceptions.rb +45 -0
- data/lib/waz/tables/service.rb +178 -0
- data/lib/waz/tables/table.rb +75 -0
- data/lib/waz/tables/table_array.rb +11 -0
- data/rakefile +23 -0
- data/tests/configuration.rb +14 -0
- data/tests/waz/blobs/blob_object_test.rb +80 -0
- data/tests/waz/blobs/container_test.rb +162 -0
- data/tests/waz/blobs/service_test.rb +282 -0
- data/tests/waz/queues/message_test.rb +33 -0
- data/tests/waz/queues/queue_test.rb +206 -0
- data/tests/waz/queues/service_test.rb +299 -0
- data/tests/waz/storage/base_tests.rb +81 -0
- data/tests/waz/storage/shared_key_core_service_test.rb +142 -0
- data/tests/waz/tables/service_test.rb +614 -0
- data/tests/waz/tables/table_test.rb +98 -0
- data/waz-storage.gemspec +29 -0
- metadata +187 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Storage
|
3
|
+
# This class is the base exception from where all the exceptions raised from this API
|
4
|
+
# inherit from. If you want to handle an exception that your code may throw and you don't
|
5
|
+
# know which specific type you should handle, handle this type of exception.
|
6
|
+
class StorageException < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# This exception raises whenever a required parameter for initializing any class isn't provided. From
|
10
|
+
# WAZ::Storage::Base up to WAZ::Queues::Queue all of them use this exception.
|
11
|
+
class InvalidOption < StorageException
|
12
|
+
def initialize(missing_option)
|
13
|
+
super("You did not provide one of the required parameters. Please provide the #{missing_option}.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# This exception is raised when the user tries to perform an operation on any Storage API class
|
18
|
+
# without previously specificying the connection options.
|
19
|
+
class NotConnected < StorageException
|
20
|
+
def initialize
|
21
|
+
super("You should establish connection before using the services, the connection configuration is required.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This exception if raised when the value given for an argument doesn't fall into the permitted values. For example
|
26
|
+
# if values on the blocklisttype aren't [all|uncommitted|committed]
|
27
|
+
class InvalidParameterValue < StorageException
|
28
|
+
def initialize(args = {})
|
29
|
+
super("The value supplied for the parameter #{args[:name]} is invalid. Permitted values are #{args[:values].join(',')}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Storage
|
3
|
+
class ValidationRules
|
4
|
+
class << self
|
5
|
+
# Validates that the Container/Queue name given matches with the requirements of Windows Azure.
|
6
|
+
#
|
7
|
+
# -Container/Queue names must start with a letter or number, and can contain only letters, numbers, and the dash (-) character.
|
8
|
+
# -Every dash (-) character must be immediately preceded and followed by a letter or number.
|
9
|
+
# -All letters in a container name must be lowercase.
|
10
|
+
# -Container/Queue names must be from 3 through 63 characters long.
|
11
|
+
def valid_name?(name)
|
12
|
+
name =~ /^[a-z0-9][a-z0-9\-]{1,}[^-]$/ && name.length < 64
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validates that the Table name given matches with the requirements of Windows Azure.
|
16
|
+
#
|
17
|
+
# -Table names must start with at least one lower / upper character.
|
18
|
+
# -Table names can have character or any digit starting from the second position.
|
19
|
+
# -Table names must be from 3 through 63 characters long.
|
20
|
+
def valid_table_name?(name)
|
21
|
+
name =~ /^([a-z]|[A-Z]){1}([a-z]|[A-Z]|\d){2,62}$/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Tables
|
3
|
+
class EdmTypeHelper
|
4
|
+
class << self
|
5
|
+
def parse_from(item)
|
6
|
+
return nil if !item.attributes['m:null'].nil? and item.attributes['m:null'] == 'true'
|
7
|
+
case item.attributes['m:type']
|
8
|
+
when 'Edm.Int16', 'Edm.Int32', 'Edm.Int64'
|
9
|
+
item.text.to_i
|
10
|
+
when 'Edm.Single', 'Edm.Double'
|
11
|
+
item.text.to_f
|
12
|
+
when 'Edm.Boolean'
|
13
|
+
item.text == 'true'
|
14
|
+
when 'Edm.DateTime'
|
15
|
+
Time.parse(item.text)
|
16
|
+
when 'Edm.Binary'
|
17
|
+
StringIO.new(Base64.decode64(item.text))
|
18
|
+
else
|
19
|
+
item.text
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_to(item)
|
24
|
+
case item.class.name
|
25
|
+
when 'String'
|
26
|
+
[item, 'Edm.String']
|
27
|
+
when 'Fixnum'
|
28
|
+
[item, 'Edm.Int32']
|
29
|
+
when 'Float'
|
30
|
+
[item, 'Edm.Double']
|
31
|
+
when 'TrueClass', 'FalseClass'
|
32
|
+
[item, 'Edm.Boolean']
|
33
|
+
when 'Time'
|
34
|
+
[item.iso8601, 'Edm.DateTime']
|
35
|
+
when 'File', 'StringIO'
|
36
|
+
item.pos = 0
|
37
|
+
[Base64.encode64(item.read), 'Edm.Binary']
|
38
|
+
else
|
39
|
+
[item, 'Edm.String']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module WAZ
|
2
|
+
module Tables
|
3
|
+
# This exception is raised while trying to create table that already exists.
|
4
|
+
class TableAlreadyExists < WAZ::Storage::StorageException
|
5
|
+
def initialize(name)
|
6
|
+
super("The table #{name} already exists on your account.")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# This exception is raised while trying to delete an unexisting table.
|
11
|
+
class TableDoesNotExist < WAZ::Storage::StorageException
|
12
|
+
def initialize(name)
|
13
|
+
super("The specified table #{name} does not exist.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# This exception is raised when an invalid table name is provided.
|
18
|
+
class InvalidTableName < WAZ::Storage::StorageException
|
19
|
+
def initialize(name)
|
20
|
+
super("The table name #{name} is invalid, it must start with at least one lower/upper characted, must be from 3 through 63 characters long and can have character or any digit starting from the second position")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# This exception is raised when provided more than the 252 properties allowed by the Rest API.
|
25
|
+
class TooManyProperties < WAZ::Storage::StorageException
|
26
|
+
def initialize(total)
|
27
|
+
super("The entity contains more properties than allowed (252). The entity has #{total} properties.")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# This exception is raised when the specified entity already exists.
|
32
|
+
class EntityAlreadyExists < WAZ::Storage::StorageException
|
33
|
+
def initialize(row_key)
|
34
|
+
super("The specified entity already exists. RowKey: #{row_key}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# This exception is raised while trying to delete an unexisting entity.
|
39
|
+
class EntityDoesNotExist < WAZ::Storage::StorageException
|
40
|
+
def initialize(key)
|
41
|
+
super("The specified entity with #{key} does not exist.")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +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
|
@@ -0,0 +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
|
75
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new do |t|
|
7
|
+
t.name = :specs
|
8
|
+
t.pattern = "tests/**/*_test.rb"
|
9
|
+
t.rcov = true
|
10
|
+
t.rcov_opts = ['--text-report', '--exclude', "exclude.*/.gem,test,Library,#{ENV['GEM_HOME']}", '--sort', 'coverage' ]
|
11
|
+
t.rspec_opts = ['-cfn']
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :docs do
|
15
|
+
Rake::RDocTask.new do |t|
|
16
|
+
t.rdoc_dir = 'rdoc'
|
17
|
+
t.title = "Windows Azure Storage library - simple gem for accessing WAZ's Storage REST API"
|
18
|
+
t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
19
|
+
t.options << '--charset' << 'utf-8'
|
20
|
+
t.rdoc_files.include('README.rdoc')
|
21
|
+
t.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
end
|