lib/azure/table/table_service.rb in stuartpreston-azure-sdk-for-ruby-0.7.1 vs lib/azure/table/table_service.rb in stuartpreston-azure-sdk-for-ruby-0.7.2
- old
+ new
@@ -1,560 +1,560 @@
-#-------------------------------------------------------------------------
-# # Copyright (c) Microsoft and contributors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#--------------------------------------------------------------------------
-require 'azure/service/storage_service'
-
-require 'azure/table/auth/shared_key'
-
-require 'azure/table/serialization'
-require 'azure/table/entity'
-
-module Azure
- module Table
- class TableService < Azure::Service::StorageService
-
- def initialize
- super(Azure::Table::Auth::SharedKey.new)
- @host = Azure.config.storage_table_host
- end
-
- # Public: Creates new table in the storage account
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- #
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd135729
- #
- # Returns nil on success
- def create_table(table_name, options={})
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- body = Azure::Table::Serialization.hash_to_entry_xml({"TableName" => table_name}).to_xml
- call(:post, collection_uri(query), body)
- nil
- end
-
- # Public: Deletes the specified table and any data it contains.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179387
- #
- # Returns nil on success
- def delete_table(table_name, options={})
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- call(:delete, table_uri(table_name, query))
- nil
- end
-
- # Public: Gets the table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # Returns the last updated time for the table
- def get_table(table_name, options={})
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- response = call(:get, table_uri(table_name, query))
- results = Azure::Table::Serialization.hash_from_entry_xml(response.body)
- results[:updated]
- end
-
- # Public: Gets a list of all tables on the account.
- #
- # ==== Attributes
- #
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:next_table_token+ - String. A token used to enumerate the next page of results, when the list of tables is
- # larger than a single operation can return at once. (optional)
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179405
- #
- # Returns an array with an extra continuation_token property on success
- def query_tables(options={})
- query = { }
- query["NextTable"] = options[:next_table_token] if options[:next_table_token]
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- uri = collection_uri(query)
-
- response = call(:get, uri)
- entries = Azure::Table::Serialization.entries_from_feed_xml(response.body) || []
-
- values = Azure::Service::EnumerationResults.new(entries)
- values.continuation_token = response.headers["x-ms-continuation-NextTableName"]
- values
- end
-
- # Public: Gets the access control list (ACL) for the table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj159100
- #
- # Returns a list of Azure::Entity::SignedIdentifier instances
- def get_table_acl(table_name, options={})
- query = { "comp" => "acl" }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- response = call(:get, generate_uri(table_name, query))
-
- signed_identifiers = []
- signed_identifiers = Azure::Table::Serialization.signed_identifiers_from_xml response.body unless response.body == nil or response.body.length < 1
- signed_identifiers
- end
-
- # Public: Sets the access control list (ACL) for the table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:signed_identifiers+ - Array. A list of Azure::Entity::SignedIdentifier instances
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/jj159102
- #
- # Returns nil on success
- def set_table_acl(table_name, options={})
- query = { "comp" => "acl" }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- uri = generate_uri(table_name, query)
- body = nil
- body = Azure::Table::Serialization.signed_identifiers_to_xml options[:signed_identifiers] if options[:signed_identifiers] && options[:signed_identifiers].length > 0
-
- call(:put, uri, body, {})
- nil
- end
-
- # Public: Inserts new entity to the table.
- #
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179433
- #
- # Returns a Azure::Entity::Table::Entity
- def insert_entity(table_name, entity_values, options={})
- body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
-
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- response = call(:post, entities_uri(table_name, nil, nil, query), body)
-
- result = Azure::Table::Serialization.hash_from_entry_xml(response.body)
-
- Entity.new do |entity|
- entity.table = table_name
- entity.updated = result[:updated]
- entity.etag = response.headers["etag"] || result[:etag]
- entity.properties = result[:properties]
- end
- end
-
- # Public: Queries entities for the given table name
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:partition_key+ - String. The partition key (optional)
- # * +:row_key+ - String. The row key (optional)
- # * +:select+ - Array. An array of property names to return (optional)
- # * +:filter+ - String. A filter expression (optional)
- # * +:top+ - Integer. A limit for the number of results returned (optional)
- # * +:continuation_token+ - Hash. The continuation token.
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179421
- #
- # Returns an array with an extra continuation_token property on success
- def query_entities(table_name, options={})
- query ={}
- query["$select"] = options[:select].join ',' if options[:select]
- query["$filter"] = options[:filter] if options[:filter]
- query["$top"] = options[:top].to_s if options[:top] unless options[:partition_key] and options[:row_key]
- query["NextPartitionKey"] = options[:continuation_token][:next_partition_key] if options[:continuation_token] and options[:continuation_token][:next_partition_key]
- query["NextRowKey"] = options[:continuation_token][:next_row_key] if options[:continuation_token] and options[:continuation_token][:next_row_key]
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- uri = entities_uri(table_name, options[:partition_key], options[:row_key], query)
- response = call(:get, uri, nil, { "DataServiceVersion" => "2.0;NetFx"})
-
- entities = Azure::Service::EnumerationResults.new
-
- results = (options[:partition_key] and options[:row_key]) ? [Azure::Table::Serialization.hash_from_entry_xml(response.body)] : Azure::Table::Serialization.entries_from_feed_xml(response.body)
-
- results.each do |result|
- entity = Entity.new do |e|
- e.table = table_name
- e.updated = result[:updated]
- e.etag = response.headers["etag"] || result[:etag]
- e.properties = result[:properties]
- end
- entities.push entity
- end if results
-
- entities.continuation_token = nil
- entities.continuation_token = {
- :next_partition_key=> response.headers["x-ms-continuation-NextPartitionKey"],
- :next_row_key => response.headers["x-ms-continuation-NextRowKey"]
- } if response.headers["x-ms-continuation-NextPartitionKey"]
-
- entities
- end
-
- # Public: Updates an existing entity in a table. The Update Entity operation replaces
- # the entire entity and can be used to remove properties.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
- # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
- # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179427
- #
- # Returns the ETag for the entity on success
- def update_entity(table_name, entity_values, options={})
- if_match = "*"
- if_match = options[:if_match] if options[:if_match]
-
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
-
- headers = {}
- headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
-
- body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
-
- response = call(:put, uri, body, headers)
- response.headers["etag"]
- end
-
- # Public: Updates an existing entity by updating the entity's properties. This operation
- # does not replace the existing entity, as the update_entity operation does.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
- # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
- # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179392
- #
- # Returns the ETag for the entity on success
- def merge_entity(table_name, entity_values, options={})
- if_match = "*"
- if_match = options[:if_match] if options[:if_match]
-
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
-
- headers = { "X-HTTP-Method"=> "MERGE" }
- headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
-
- body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
-
- response = call(:post, uri, body, headers)
- response.headers["etag"]
- end
-
- # Public: Inserts or updates an existing entity within a table by merging new property values into the entity.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/hh452241
- #
- # Returns the ETag for the entity on success
- def insert_or_merge_entity(table_name, entity_values, options={})
- options[:create_if_not_exists] = true
- merge_entity(table_name, entity_values, options)
- end
-
- # Public: Inserts or updates a new entity into a table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/hh452242
- #
- # Returns the ETag for the entity on success
- def insert_or_replace_entity(table_name, entity_values, options={})
- options[:create_if_not_exists] = true
- update_entity(table_name, entity_values, options)
- end
-
- # Public: Deletes an existing entity in the table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +partition_key+ - String. The partition key
- # * +row_key+ - String. The row key
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd135727
- #
- # Returns nil on success
- def delete_entity(table_name, partition_key, row_key, options={})
- if_match = "*"
- if_match = options[:if_match] if options[:if_match]
-
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- call(:delete, entities_uri(table_name, partition_key, row_key, query), nil, { "If-Match"=> if_match })
- nil
- end
-
- # Public: Executes a batch of operations.
- #
- # ==== Attributes
- #
- # * +batch+ - The Azure::Table::Batch instance to execute.
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # See http://msdn.microsoft.com/en-us/library/windowsazure/dd894038
- #
- # Returns an array of results, one for each operation in the batch
- def execute_batch(batch, options={})
- headers = {
- "Content-Type"=> "multipart/mixed; boundary=#{batch.batch_id}",
- "Accept"=> 'application/atom+xml,application/xml',
- 'Accept-Charset'=> 'UTF-8'
- }
-
- query = { }
- query["timeout"] = options[:timeout].to_s if options[:timeout]
-
- body = batch.to_body
- response = call(:post, generate_uri("/$batch", query), body, headers)
- batch.parse_response(response)
- end
-
- # Public: Gets an existing entity in the table.
- #
- # ==== Attributes
- #
- # * +table_name+ - String. The table name
- # * +partition_key+ - String. The partition key
- # * +row_key+ - String. The row key
- # * +options+ - Hash. Optional parameters.
- #
- # ==== Options
- #
- # Accepted key/value pairs in options parameter are:
- # * +:timeout+ - Integer. A timeout in seconds.
- #
- # Returns an Azure::Table::Entity instance on success
- def get_entity(table_name, partition_key, row_key, options={})
- options[:partition_key] = partition_key
- options[:row_key] = row_key
- results = query_entities(table_name, options)
- results.length > 0 ? results[0] : nil
- end
-
- # Protected: Generate the URI for the collection of tables.
- #
- # Returns a URI
- protected
- def collection_uri(query={})
- generate_uri("Tables", query)
- end
-
- # Public: Generate the URI for a specific table.
- #
- # ==== Attributes
- #
- # * +name+ - The table name. If this is a URI, we just return this
- #
- # Returns a URI
- public
- def table_uri(name, query={})
- return name if name.kind_of? ::URI
- generate_uri("Tables('#{name}')", query)
- end
-
- # Public: Generate the URI for an entity or group of entities in a table.
- # If both the 'partition_key' and 'row_key' are specified, then the URI
- # will match the entity under those specific keys.
- #
- # ==== Attributes
- #
- # * +table_name+ - The table name
- # * +partition_key+ - The desired partition key (optional)
- # * +row_key+ - The desired row key (optional)
- #
- # Returns a URI
- public
- def entities_uri(table_name, partition_key=nil, row_key=nil, query={})
- return table_name if table_name.kind_of? ::URI
-
- path = if partition_key && row_key
- "%s(PartitionKey='%s',RowKey='%s')" % [
- table_name.encode("UTF-8"), encodeODataUriValue(partition_key.encode("UTF-8")), encodeODataUriValue(row_key.encode("UTF-8"))
- ]
- else
- "%s()" % table_name.encode("UTF-8")
- end
-
- uri = generate_uri(path)
- qs = []
- if query
- query.each do | key, val |
- key = key.encode("UTF-8")
- val = val.encode("UTF-8")
-
- if key[0] == "$"
- qs.push "#{key}#{::URI.encode_www_form(""=>val)}"
- else
- qs.push ::URI.encode_www_form(key=>val)
- end
- end
- end
- uri.query = qs.join '&' if qs.length > 0
- uri
- end
-
- protected
- def encodeODataUriValues(values)
- new_values = []
- values.each do |value|
- new_values.push encodeODataUriValue(value)
- end
- new_values
- end
-
- protected
- def encodeODataUriValue(value)
- # Replace each single quote (') with double single quotes ('') not double
- # quotes (")
- value = value.gsub("'", "''")
-
- # Encode the special URL characters
- value = URI.escape(value)
-
- value
- end
- end
- end
+#-------------------------------------------------------------------------
+# # Copyright (c) Microsoft and contributors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#--------------------------------------------------------------------------
+require 'azure/service/storage_service'
+
+require 'azure/table/auth/shared_key'
+
+require 'azure/table/serialization'
+require 'azure/table/entity'
+
+module Azure
+ module Table
+ class TableService < Azure::Service::StorageService
+
+ def initialize
+ super(Azure::Table::Auth::SharedKey.new)
+ @host = Azure.config.storage_table_host
+ end
+
+ # Public: Creates new table in the storage account
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ #
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd135729
+ #
+ # Returns nil on success
+ def create_table(table_name, options={})
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ body = Azure::Table::Serialization.hash_to_entry_xml({"TableName" => table_name}).to_xml
+ call(:post, collection_uri(query), body)
+ nil
+ end
+
+ # Public: Deletes the specified table and any data it contains.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179387
+ #
+ # Returns nil on success
+ def delete_table(table_name, options={})
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ call(:delete, table_uri(table_name, query))
+ nil
+ end
+
+ # Public: Gets the table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # Returns the last updated time for the table
+ def get_table(table_name, options={})
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ response = call(:get, table_uri(table_name, query))
+ results = Azure::Table::Serialization.hash_from_entry_xml(response.body)
+ results[:updated]
+ end
+
+ # Public: Gets a list of all tables on the account.
+ #
+ # ==== Attributes
+ #
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:next_table_token+ - String. A token used to enumerate the next page of results, when the list of tables is
+ # larger than a single operation can return at once. (optional)
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179405
+ #
+ # Returns an array with an extra continuation_token property on success
+ def query_tables(options={})
+ query = { }
+ query["NextTable"] = options[:next_table_token] if options[:next_table_token]
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ uri = collection_uri(query)
+
+ response = call(:get, uri)
+ entries = Azure::Table::Serialization.entries_from_feed_xml(response.body) || []
+
+ values = Azure::Service::EnumerationResults.new(entries)
+ values.continuation_token = response.headers["x-ms-continuation-NextTableName"]
+ values
+ end
+
+ # Public: Gets the access control list (ACL) for the table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj159100
+ #
+ # Returns a list of Azure::Entity::SignedIdentifier instances
+ def get_table_acl(table_name, options={})
+ query = { "comp" => "acl" }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ response = call(:get, generate_uri(table_name, query))
+
+ signed_identifiers = []
+ signed_identifiers = Azure::Table::Serialization.signed_identifiers_from_xml response.body unless response.body == nil or response.body.length < 1
+ signed_identifiers
+ end
+
+ # Public: Sets the access control list (ACL) for the table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:signed_identifiers+ - Array. A list of Azure::Entity::SignedIdentifier instances
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/jj159102
+ #
+ # Returns nil on success
+ def set_table_acl(table_name, options={})
+ query = { "comp" => "acl" }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ uri = generate_uri(table_name, query)
+ body = nil
+ body = Azure::Table::Serialization.signed_identifiers_to_xml options[:signed_identifiers] if options[:signed_identifiers] && options[:signed_identifiers].length > 0
+
+ call(:put, uri, body, {})
+ nil
+ end
+
+ # Public: Inserts new entity to the table.
+ #
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179433
+ #
+ # Returns a Azure::Entity::Table::Entity
+ def insert_entity(table_name, entity_values, options={})
+ body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
+
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ response = call(:post, entities_uri(table_name, nil, nil, query), body)
+
+ result = Azure::Table::Serialization.hash_from_entry_xml(response.body)
+
+ Entity.new do |entity|
+ entity.table = table_name
+ entity.updated = result[:updated]
+ entity.etag = response.headers["etag"] || result[:etag]
+ entity.properties = result[:properties]
+ end
+ end
+
+ # Public: Queries entities for the given table name
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:partition_key+ - String. The partition key (optional)
+ # * +:row_key+ - String. The row key (optional)
+ # * +:select+ - Array. An array of property names to return (optional)
+ # * +:filter+ - String. A filter expression (optional)
+ # * +:top+ - Integer. A limit for the number of results returned (optional)
+ # * +:continuation_token+ - Hash. The continuation token.
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179421
+ #
+ # Returns an array with an extra continuation_token property on success
+ def query_entities(table_name, options={})
+ query ={}
+ query["$select"] = options[:select].join ',' if options[:select]
+ query["$filter"] = options[:filter] if options[:filter]
+ query["$top"] = options[:top].to_s if options[:top] unless options[:partition_key] and options[:row_key]
+ query["NextPartitionKey"] = options[:continuation_token][:next_partition_key] if options[:continuation_token] and options[:continuation_token][:next_partition_key]
+ query["NextRowKey"] = options[:continuation_token][:next_row_key] if options[:continuation_token] and options[:continuation_token][:next_row_key]
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ uri = entities_uri(table_name, options[:partition_key], options[:row_key], query)
+ response = call(:get, uri, nil, { "DataServiceVersion" => "2.0;NetFx"})
+
+ entities = Azure::Service::EnumerationResults.new
+
+ results = (options[:partition_key] and options[:row_key]) ? [Azure::Table::Serialization.hash_from_entry_xml(response.body)] : Azure::Table::Serialization.entries_from_feed_xml(response.body)
+
+ results.each do |result|
+ entity = Entity.new do |e|
+ e.table = table_name
+ e.updated = result[:updated]
+ e.etag = response.headers["etag"] || result[:etag]
+ e.properties = result[:properties]
+ end
+ entities.push entity
+ end if results
+
+ entities.continuation_token = nil
+ entities.continuation_token = {
+ :next_partition_key=> response.headers["x-ms-continuation-NextPartitionKey"],
+ :next_row_key => response.headers["x-ms-continuation-NextRowKey"]
+ } if response.headers["x-ms-continuation-NextPartitionKey"]
+
+ entities
+ end
+
+ # Public: Updates an existing entity in a table. The Update Entity operation replaces
+ # the entire entity and can be used to remove properties.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
+ # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
+ # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179427
+ #
+ # Returns the ETag for the entity on success
+ def update_entity(table_name, entity_values, options={})
+ if_match = "*"
+ if_match = options[:if_match] if options[:if_match]
+
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
+
+ headers = {}
+ headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
+
+ body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
+
+ response = call(:put, uri, body, headers)
+ response.headers["etag"]
+ end
+
+ # Public: Updates an existing entity by updating the entity's properties. This operation
+ # does not replace the existing entity, as the update_entity operation does.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
+ # * +:create_if_not_exists+ - Boolean. If true, and partition_key and row_key do not reference and existing entity,
+ # that entity will be inserted. If false, the operation will fail. (optional, Default=false)
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd179392
+ #
+ # Returns the ETag for the entity on success
+ def merge_entity(table_name, entity_values, options={})
+ if_match = "*"
+ if_match = options[:if_match] if options[:if_match]
+
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ uri = entities_uri(table_name, entity_values["PartitionKey"], entity_values["RowKey"], query)
+
+ headers = { "X-HTTP-Method"=> "MERGE" }
+ headers["If-Match"] = if_match || "*" unless options[:create_if_not_exists]
+
+ body = Azure::Table::Serialization.hash_to_entry_xml(entity_values).to_xml
+
+ response = call(:post, uri, body, headers)
+ response.headers["etag"]
+ end
+
+ # Public: Inserts or updates an existing entity within a table by merging new property values into the entity.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/hh452241
+ #
+ # Returns the ETag for the entity on success
+ def insert_or_merge_entity(table_name, entity_values, options={})
+ options[:create_if_not_exists] = true
+ merge_entity(table_name, entity_values, options)
+ end
+
+ # Public: Inserts or updates a new entity into a table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +entity_values+ - Hash. A hash of the name/value pairs for the entity.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/hh452242
+ #
+ # Returns the ETag for the entity on success
+ def insert_or_replace_entity(table_name, entity_values, options={})
+ options[:create_if_not_exists] = true
+ update_entity(table_name, entity_values, options)
+ end
+
+ # Public: Deletes an existing entity in the table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +partition_key+ - String. The partition key
+ # * +row_key+ - String. The row key
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:if_match+ - String. A matching condition which is required for update (optional, Default="*")
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd135727
+ #
+ # Returns nil on success
+ def delete_entity(table_name, partition_key, row_key, options={})
+ if_match = "*"
+ if_match = options[:if_match] if options[:if_match]
+
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ call(:delete, entities_uri(table_name, partition_key, row_key, query), nil, { "If-Match"=> if_match })
+ nil
+ end
+
+ # Public: Executes a batch of operations.
+ #
+ # ==== Attributes
+ #
+ # * +batch+ - The Azure::Table::Batch instance to execute.
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # See http://msdn.microsoft.com/en-us/library/windowsazure/dd894038
+ #
+ # Returns an array of results, one for each operation in the batch
+ def execute_batch(batch, options={})
+ headers = {
+ "Content-Type"=> "multipart/mixed; boundary=#{batch.batch_id}",
+ "Accept"=> 'application/atom+xml,application/xml',
+ 'Accept-Charset'=> 'UTF-8'
+ }
+
+ query = { }
+ query["timeout"] = options[:timeout].to_s if options[:timeout]
+
+ body = batch.to_body
+ response = call(:post, generate_uri("/$batch", query), body, headers)
+ batch.parse_response(response)
+ end
+
+ # Public: Gets an existing entity in the table.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - String. The table name
+ # * +partition_key+ - String. The partition key
+ # * +row_key+ - String. The row key
+ # * +options+ - Hash. Optional parameters.
+ #
+ # ==== Options
+ #
+ # Accepted key/value pairs in options parameter are:
+ # * +:timeout+ - Integer. A timeout in seconds.
+ #
+ # Returns an Azure::Table::Entity instance on success
+ def get_entity(table_name, partition_key, row_key, options={})
+ options[:partition_key] = partition_key
+ options[:row_key] = row_key
+ results = query_entities(table_name, options)
+ results.length > 0 ? results[0] : nil
+ end
+
+ # Protected: Generate the URI for the collection of tables.
+ #
+ # Returns a URI
+ protected
+ def collection_uri(query={})
+ generate_uri("Tables", query)
+ end
+
+ # Public: Generate the URI for a specific table.
+ #
+ # ==== Attributes
+ #
+ # * +name+ - The table name. If this is a URI, we just return this
+ #
+ # Returns a URI
+ public
+ def table_uri(name, query={})
+ return name if name.kind_of? ::URI
+ generate_uri("Tables('#{name}')", query)
+ end
+
+ # Public: Generate the URI for an entity or group of entities in a table.
+ # If both the 'partition_key' and 'row_key' are specified, then the URI
+ # will match the entity under those specific keys.
+ #
+ # ==== Attributes
+ #
+ # * +table_name+ - The table name
+ # * +partition_key+ - The desired partition key (optional)
+ # * +row_key+ - The desired row key (optional)
+ #
+ # Returns a URI
+ public
+ def entities_uri(table_name, partition_key=nil, row_key=nil, query={})
+ return table_name if table_name.kind_of? ::URI
+
+ path = if partition_key && row_key
+ "%s(PartitionKey='%s',RowKey='%s')" % [
+ table_name.encode("UTF-8"), encodeODataUriValue(partition_key.encode("UTF-8")), encodeODataUriValue(row_key.encode("UTF-8"))
+ ]
+ else
+ "%s()" % table_name.encode("UTF-8")
+ end
+
+ uri = generate_uri(path)
+ qs = []
+ if query
+ query.each do | key, val |
+ key = key.encode("UTF-8")
+ val = val.encode("UTF-8")
+
+ if key[0] == "$"
+ qs.push "#{key}#{::URI.encode_www_form(""=>val)}"
+ else
+ qs.push ::URI.encode_www_form(key=>val)
+ end
+ end
+ end
+ uri.query = qs.join '&' if qs.length > 0
+ uri
+ end
+
+ protected
+ def encodeODataUriValues(values)
+ new_values = []
+ values.each do |value|
+ new_values.push encodeODataUriValue(value)
+ end
+ new_values
+ end
+
+ protected
+ def encodeODataUriValue(value)
+ # Replace each single quote (') with double single quotes ('') not double
+ # quotes (")
+ value = value.gsub("'", "''")
+
+ # Encode the special URL characters
+ value = URI.escape(value)
+
+ value
+ end
+ end
+ end
end
\ No newline at end of file