simplydb 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -21
- data/Gemfile +4 -0
- data/README.md +37 -0
- data/Rakefile +10 -50
- data/lib/simplydb.rb +2 -3
- data/lib/simplydb/client.rb +71 -58
- data/lib/simplydb/error.rb +62 -57
- data/lib/simplydb/interface.rb +36 -54
- data/lib/simplydb/server.rb +74 -0
- data/lib/simplydb/version.rb +3 -0
- data/simplydb.gemspec +25 -77
- data/spec/client_spec.rb +17 -5
- data/spec/error_spec.rb +15 -5
- data/spec/fixtures/vcr/create_env.yml +313 -0
- data/spec/fixtures/vcr/delete_domains.yml +119 -0
- data/spec/fixtures/vcr/delete_items.yml +81 -0
- data/spec/fixtures/vcr/delete_items_all.yml +79 -0
- data/spec/fixtures/vcr/destroy_env.yml +197 -0
- data/spec/fixtures/vcr/get_all_items.yml +43 -0
- data/spec/fixtures/vcr/get_domains.yml +41 -0
- data/spec/fixtures/vcr/get_items.yml +42 -0
- data/spec/fixtures/vcr/put_domains.yml +119 -0
- data/spec/fixtures/vcr/put_items.yml +81 -0
- data/spec/fixtures/vcr/show_domains.yml +42 -0
- data/spec/interface_spec.rb +75 -92
- data/spec/server_spec.rb +236 -0
- data/spec/spec_helper.rb +19 -11
- data/spec/support/vcr.rb +7 -0
- metadata +131 -56
- data/.document +0 -5
- data/LICENSE +0 -20
- data/README.rdoc +0 -37
- data/VERSION +0 -1
- data/examples/interface.rb +0 -19
- data/examples/record.rb +0 -45
- data/lib/simplydb/clients/typhoeus.rb +0 -35
- data/lib/simplydb/extensions.rb +0 -21
- data/lib/simplydb/record.rb +0 -2
- data/lib/simplydb/record/base.rb +0 -282
- data/spec/extensions_spec.rb +0 -15
- data/spec/record/base_spec.rb +0 -214
- data/spec/spec.opts +0 -2
data/.gitignore
CHANGED
@@ -1,21 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
tmtags
|
7
|
-
|
8
|
-
## EMACS
|
9
|
-
*~
|
10
|
-
\#*
|
11
|
-
.\#*
|
12
|
-
|
13
|
-
## VIM
|
14
|
-
*.swp
|
15
|
-
|
16
|
-
## PROJECT::GENERAL
|
17
|
-
coverage
|
18
|
-
rdoc
|
19
|
-
pkg
|
20
|
-
|
21
|
-
## PROJECT::SPECIFIC
|
1
|
+
pkg/*
|
2
|
+
*.gem
|
3
|
+
.bundle
|
4
|
+
Gemfile.lock
|
5
|
+
.idea/*
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# simplydb
|
2
|
+
|
3
|
+
A minimal interface to Amazon SimpleDB that has separation of interfaces. Build to support a Sinatra app that can be used as a JSON <-> SimpleDB proxy.
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'simplydb'
|
7
|
+
|
8
|
+
interface = SimplyDB::Interface.new({
|
9
|
+
:access_key => ENV['AWS_ACCESS_KEY'],
|
10
|
+
:secret_key => ENV['AWS_SECRET_KEY']
|
11
|
+
})
|
12
|
+
|
13
|
+
if interface.create_domain("MyDomain")
|
14
|
+
interface.put_attributes('MyDomain', 'Item123', {'color'=>['red','brick','garnet']})
|
15
|
+
|
16
|
+
attributes = interface.get_attributes('MyDomain', 'Item123')
|
17
|
+
puts "Item123 = #{attributes.inspect}"
|
18
|
+
|
19
|
+
items = interface.select("select color from MyDomain where color = 'brick'")
|
20
|
+
puts "Items = #{items.inspect}"
|
21
|
+
|
22
|
+
interface.delete_domain("MyDomain")
|
23
|
+
end
|
24
|
+
|
25
|
+
## Note on Patches/Pull Requests
|
26
|
+
|
27
|
+
* Fork the project.
|
28
|
+
* Make your feature addition or bug fix.
|
29
|
+
* Add tests for it. This is important so I don't break it in a
|
30
|
+
future version unintentionally.
|
31
|
+
* Commit, do not mess with rakefile, version, or history.
|
32
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
33
|
+
* Send me a pull request. Bonus points for topic branches.
|
34
|
+
|
35
|
+
## Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2010 JT Archie. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,54 +1,14 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'bundler'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "simplydb"
|
8
|
-
gem.summary = %Q{A minimal interface to Amazon SimpleDB.}
|
9
|
-
gem.description = %Q{A minimal interface to Amazon SimpleDB that has separation of interfaces. From the low level HTTP request access to high level Ruby abstraction ORM.}
|
10
|
-
gem.email = "jtarchie@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/jtarchie/simplydb"
|
12
|
-
gem.authors = ["JT Archie"]
|
13
|
-
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
-
gem.add_dependency "typhoeus", ">= 0.1.27"
|
15
|
-
gem.add_dependency "nokogiri", ">= 1.4.2"
|
16
|
-
gem.add_dependency "uuidtools", ">= 2.1.1"
|
17
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
-
end
|
19
|
-
Jeweler::GemcutterTasks.new
|
20
|
-
rescue LoadError
|
21
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
22
|
-
end
|
23
|
-
|
24
|
-
require 'spec/rake/spectask'
|
25
|
-
Spec::Rake::SpecTask.new(:spec) do |spec|
|
26
|
-
spec.libs << 'lib' << 'spec'
|
27
|
-
spec.spec_files = FileList['spec/**/*_spec.rb']
|
28
|
-
end
|
29
|
-
|
30
|
-
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
31
|
-
spec.libs << 'lib' << 'spec'
|
32
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
33
|
-
spec.rcov = true
|
34
|
-
end
|
4
|
+
Bundler::GemHelper.install_tasks
|
35
5
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
exec("irb -I lib/ -r 'simplydb' -r 'simplydb/record/base'")
|
6
|
+
desc "Run specs"
|
7
|
+
task :spec do
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
9
|
+
t.rspec_opts = %w{--colour --format progress}
|
10
|
+
t.pattern = 'spec/*_spec.rb'
|
11
|
+
end
|
43
12
|
end
|
44
|
-
task :console => :irb
|
45
13
|
|
46
|
-
|
47
|
-
Rake::RDocTask.new do |rdoc|
|
48
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
-
|
50
|
-
rdoc.rdoc_dir = 'rdoc'
|
51
|
-
rdoc.title = "simplydb #{version}"
|
52
|
-
rdoc.rdoc_files.include('README*')
|
53
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
-
end
|
14
|
+
task :default => :spec
|
data/lib/simplydb.rb
CHANGED
data/lib/simplydb/client.rb
CHANGED
@@ -1,66 +1,79 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'base64'
|
4
|
-
require '
|
5
|
-
require 'simplydb/clients/typhoeus'
|
4
|
+
require 'rest_client'
|
6
5
|
|
7
6
|
module SimplyDB
|
8
7
|
class Client
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@options[:
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
8
|
+
attr_accessor :options, :http_client
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = {
|
12
|
+
:protocol => 'https://',
|
13
|
+
:host => 'sdb.amazonaws.com',
|
14
|
+
:port => 443,
|
15
|
+
:path => "/",
|
16
|
+
:signature_version => '2',
|
17
|
+
:version => '2009-04-15',
|
18
|
+
:signature_method => 'HmacSHA256',
|
19
|
+
}.merge(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def base_url
|
23
|
+
"#{@options[:protocol]}#{@options[:host]}:#{@options[:port]}#{@options[:path]}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def string_to_sign(method, params)
|
27
|
+
return "#{method.to_s.upcase}\n#{options[:host]}\n/\n" + escape_hash(params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_signature(method, params)
|
31
|
+
Base64.encode64(
|
32
|
+
OpenSSL::HMAC.digest(
|
33
|
+
OpenSSL::Digest::Digest.new('sha256'),
|
34
|
+
@options[:secret_key],
|
35
|
+
string_to_sign(method, params)
|
36
|
+
)
|
37
|
+
).chomp
|
38
|
+
end
|
39
|
+
|
40
|
+
def params_with_signature(method, params)
|
41
|
+
params.merge!({
|
42
|
+
'AWSAccessKeyId' => @options[:access_key],
|
43
|
+
'SignatureVersion' => @options[:signature_version],
|
44
|
+
'Timestamp' => Time.now.iso8601,
|
45
|
+
'Version' => @options[:version],
|
46
|
+
'SignatureMethod' => @options[:signature_method]
|
47
|
+
})
|
48
|
+
params['Signature'] = generate_signature(method, params)
|
49
|
+
params
|
50
|
+
end
|
51
|
+
|
52
|
+
def call(method, params, &block)
|
53
|
+
params = params_with_signature(method, params)
|
54
|
+
response = case method.to_sym
|
55
|
+
# when :get
|
56
|
+
# RestClient.get(base_url << "?#{escape_hash(params)}")
|
57
|
+
when :post
|
58
|
+
RestClient.post(base_url, params)
|
59
|
+
else
|
60
|
+
raise "Not support request method #{method}"
|
61
|
+
end
|
62
|
+
block.call(response.body)
|
63
|
+
rescue RestClient::BadRequest => e
|
64
|
+
block.call(e.response.body)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def escape_value(string)
|
70
|
+
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
|
71
|
+
'%' + $1.unpack('H2' * $1.size).join('%').upcase
|
72
|
+
end.gsub(' ', '%20')
|
73
|
+
end
|
74
|
+
|
75
|
+
def escape_hash(params = {})
|
76
|
+
return params.collect{|k,v| [k.to_s, v.to_s]}.sort.collect { |key, value| [escape_value(key), escape_value(value)].join('=') }.join('&')
|
77
|
+
end
|
64
78
|
end
|
65
|
-
end
|
66
79
|
end
|
data/lib/simplydb/error.rb
CHANGED
@@ -1,60 +1,65 @@
|
|
1
1
|
module SimplyDB
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class ConditionalCheckFailed < RuntimeError; end
|
9
|
-
class ExistsAndExpectedValue < RuntimeError; end
|
10
|
-
class FeatureDeprecated < RuntimeError; end
|
11
|
-
class IncompleteExpectedExpression < RuntimeError; end
|
12
|
-
class InternalError < RuntimeError; end
|
13
|
-
class InvalidAction < RuntimeError; end
|
14
|
-
class InvalidHTTPAuthHeader < RuntimeError; end
|
15
|
-
class InvalidHttpRequest < RuntimeError; end
|
16
|
-
class InvalidLiteral < RuntimeError; end
|
17
|
-
class InvalidNextToken < RuntimeError; end
|
18
|
-
class InvalidNumberPredicates < RuntimeError; end
|
19
|
-
class InvalidNumberValueTests < RuntimeError; end
|
20
|
-
class InvalidParameterCombination < RuntimeError; end
|
21
|
-
class InvalidParameterValue < RuntimeError; end
|
22
|
-
class InvalidQueryExpression < RuntimeError; end
|
23
|
-
class InvalidResponseGroups < RuntimeError; end
|
24
|
-
class InvalidService < RuntimeError; end
|
25
|
-
class InvalidSOAPRequest < RuntimeError; end
|
26
|
-
class InvalidSortExpression < RuntimeError; end
|
27
|
-
class InvalidURI < RuntimeError; end
|
28
|
-
class InvalidWSAddressingProperty < RuntimeError; end
|
29
|
-
class InvalidWSDLVersion < RuntimeError; end
|
30
|
-
class MalformedSOAPSignature < RuntimeError; end
|
31
|
-
class MissingAction < RuntimeError; end
|
32
|
-
class MissingParameter < RuntimeError; end
|
33
|
-
class MissingWSAddressingProperty < RuntimeError; end
|
34
|
-
class MultipleExistsConditions < RuntimeError; end
|
35
|
-
class MultipleExpectedNames < RuntimeError; end
|
36
|
-
class MultipleExpectedValues < RuntimeError; end
|
37
|
-
class MultiValuedAttribute < RuntimeError; end
|
38
|
-
class NoSuchDomain < RuntimeError; end
|
39
|
-
class NoSuchVersion < RuntimeError; end
|
40
|
-
class NotYetImplemented < RuntimeError; end
|
41
|
-
class NumberDomainsExceeded < RuntimeError; end
|
42
|
-
class NumberDomainAttributesExceeded < RuntimeError; end
|
43
|
-
class NumberDomainBytesExceeded < RuntimeError; end
|
44
|
-
class NumberItemAttributesExceeded < RuntimeError; end
|
45
|
-
class NumberSubmittedAttributesExceeded < RuntimeError; end
|
46
|
-
class NumberSubmittedItemsExceeded < RuntimeError; end
|
47
|
-
class RequestExpired < RuntimeError; end
|
48
|
-
class RequestTimeout < RuntimeError; end
|
49
|
-
class ServiceUnavailable < RuntimeError; end
|
50
|
-
class TooManyRequestedAttributes < RuntimeError; end
|
51
|
-
class UnsupportedHttpVerb < RuntimeError; end
|
52
|
-
class UnsupportedNextToken < RuntimeError; end
|
53
|
-
class URITooLong < RuntimeError; end
|
54
|
-
|
55
|
-
#Standard AWS errors
|
56
|
-
class SignatureDoesNotMatch < RuntimeError; end
|
57
|
-
class InvalidClientTokenId < RuntimeError; end
|
58
|
-
class InvalidRequest < RuntimeError; end
|
2
|
+
class Error < RuntimeError
|
3
|
+
attr_accessor :http_status_code, :name
|
4
|
+
def initialize(name, http_status_code)
|
5
|
+
@name = name
|
6
|
+
@http_status_code = http_status_code
|
7
|
+
end
|
59
8
|
end
|
9
|
+
|
10
|
+
AccessFailure = Error.new("AccessFailure",403)
|
11
|
+
AttributeDoesNotExist = Error.new("AttributeDoesNotExist",404)
|
12
|
+
AuthFailure = Error.new("AuthFailure",403)
|
13
|
+
AuthMissingFailure = Error.new("AuthMissingFailure",403)
|
14
|
+
ConditionalCheckFailed = Error.new("ConditionalCheckFailed",409)
|
15
|
+
ExistsAndExpectedValue = Error.new("ExistsAndExpectedValue",400)
|
16
|
+
FeatureDeprecated = Error.new("FeatureDeprecated",400)
|
17
|
+
IncompleteExpectedExpression = Error.new("IncompleteExpectedExpression",400)
|
18
|
+
InternalError = Error.new("InternalError",500)
|
19
|
+
InvalidAction = Error.new("InvalidAction",400)
|
20
|
+
InvalidHTTPAuthHeader = Error.new("InvalidHTTPAuthHeader",400)
|
21
|
+
InvalidHttpRequest = Error.new("InvalidHttpRequest",400)
|
22
|
+
InvalidLiteral = Error.new("InvalidLiteral",400)
|
23
|
+
InvalidNextToken = Error.new("InvalidNextToken",400)
|
24
|
+
InvalidNumberPredicates = Error.new("InvalidNumberPredicates",400)
|
25
|
+
InvalidNumberValueTests = Error.new("InvalidNumberValueTests",400)
|
26
|
+
InvalidParameterCombination = Error.new("InvalidParameterCombination",400)
|
27
|
+
InvalidParameterValue = Error.new("InvalidParameterValue",400)
|
28
|
+
InvalidQueryExpression = Error.new("InvalidQueryExpression",400)
|
29
|
+
InvalidResponseGroups = Error.new("InvalidResponseGroups",400)
|
30
|
+
InvalidService = Error.new("InvalidService",400)
|
31
|
+
InvalidSOAPRequest = Error.new("InvalidSOAPRequest",400)
|
32
|
+
InvalidSortExpression = Error.new("InvalidSortExpression",400)
|
33
|
+
InvalidURI = Error.new("InvalidURI",400)
|
34
|
+
InvalidWSAddressingProperty = Error.new("InvalidWSAddressingProperty",400)
|
35
|
+
InvalidWSDLVersion = Error.new("InvalidWSDLVersion",400)
|
36
|
+
MalformedSOAPSignature = Error.new("MalformedSOAPSignature",403)
|
37
|
+
MissingAction = Error.new("MissingAction",400)
|
38
|
+
MissingParameter = Error.new("MissingParameter",400)
|
39
|
+
MissingWSAddressingProperty = Error.new("MissingWSAddressingProperty",400)
|
40
|
+
MultipleExistsConditions = Error.new("MultipleExistsConditions",400)
|
41
|
+
MultipleExpectedNames = Error.new("MultipleExpectedNames",400)
|
42
|
+
MultipleExpectedValues = Error.new("MultipleExpectedValues",400)
|
43
|
+
MultiValuedAttribute = Error.new("MultiValuedAttribute",409)
|
44
|
+
NoSuchDomain = Error.new("NoSuchDomain",400)
|
45
|
+
NoSuchVersion = Error.new("NoSuchVersion",400)
|
46
|
+
NotYetImplemented = Error.new("NotYetImplemented",401)
|
47
|
+
NumberDomainsExceeded = Error.new("NumberDomainsExceeded",409)
|
48
|
+
NumberDomainAttributesExceeded = Error.new("NumberDomainAttributesExceeded",409)
|
49
|
+
NumberDomainBytesExceeded = Error.new("NumberDomainBytesExceeded",409)
|
50
|
+
NumberItemAttributesExceeded = Error.new("NumberItemAttributesExceeded",409)
|
51
|
+
NumberSubmittedAttributesExceeded = Error.new("NumberSubmittedAttributesExceeded",409)
|
52
|
+
NumberSubmittedItemsExceeded = Error.new("NumberSubmittedItemsExceeded",409)
|
53
|
+
RequestExpired = Error.new("RequestExpired",400)
|
54
|
+
RequestTimeout = Error.new("RequestTimeout",408)
|
55
|
+
ServiceUnavailable = Error.new("ServiceUnavailable",503)
|
56
|
+
TooManyRequestedAttributes = Error.new("TooManyRequestedAttributes",400)
|
57
|
+
UnsupportedHttpVerb = Error.new("UnsupportedHttpVerb",400)
|
58
|
+
UnsupportedNextToken = Error.new("UnsupportedNextToken",400)
|
59
|
+
URITooLong = Error.new("URITooLong",400)
|
60
|
+
|
61
|
+
#Standard AWS errors
|
62
|
+
SignatureDoesNotMatch = Error.new("SignatureDoesNotMatch",400)
|
63
|
+
InvalidClientTokenId = Error.new("InvalidClientTokenId",400)
|
64
|
+
InvalidRequest = Error.new("InvalidRequest",400)
|
60
65
|
end
|
data/lib/simplydb/interface.rb
CHANGED
@@ -7,43 +7,35 @@ module SimplyDB
|
|
7
7
|
@options = {}.merge(options)
|
8
8
|
@client = SimplyDB::Client.new(options)
|
9
9
|
end
|
10
|
-
|
11
|
-
def create_domain(name
|
10
|
+
|
11
|
+
def create_domain(name)
|
12
12
|
call({'Action' => 'CreateDomain', 'DomainName' => name}) do |doc|
|
13
|
-
|
14
|
-
block.call(ret_val) if block_given?
|
15
|
-
ret_val
|
13
|
+
doc.css("CreateDomainResponse").length > 0
|
16
14
|
end
|
17
15
|
end
|
18
|
-
|
19
|
-
def delete_domain(name
|
16
|
+
|
17
|
+
def delete_domain(name)
|
20
18
|
call({'Action' => 'DeleteDomain', 'DomainName' => name}) do |doc|
|
21
|
-
|
22
|
-
block.call(ret_val) if block_given?
|
23
|
-
ret_val
|
19
|
+
doc.css("DeleteDomainResponse").length > 0
|
24
20
|
end
|
25
21
|
end
|
26
|
-
|
27
|
-
def list_domains
|
22
|
+
|
23
|
+
def list_domains
|
28
24
|
call({'Action' => 'ListDomains'}) do |doc|
|
29
|
-
|
30
|
-
block.call(domains) if block_given?
|
31
|
-
domains
|
25
|
+
doc.css('DomainName').collect{|d| d.text}
|
32
26
|
end
|
33
27
|
end
|
34
|
-
|
35
|
-
def domain_metadata(name
|
28
|
+
|
29
|
+
def domain_metadata(name)
|
36
30
|
call({'Action' => 'DomainMetadata','DomainName' => name}) do |doc|
|
37
|
-
|
31
|
+
doc.css("DomainMetadataResult").first.children.inject({}) do |memo, child|
|
38
32
|
memo[child.name] = child.text
|
39
33
|
memo
|
40
34
|
end
|
41
|
-
block.call(attributes) if block_given?
|
42
|
-
attributes
|
43
35
|
end
|
44
36
|
end
|
45
|
-
|
46
|
-
def put_attributes(name, id, attributes = {}, expected = {}, replace = false
|
37
|
+
|
38
|
+
def put_attributes(name, id, attributes = {}, expected = {}, replace = false)
|
47
39
|
params = define_attributes(attributes, expected, replace)
|
48
40
|
params.merge!({
|
49
41
|
'DomainName' => name,
|
@@ -51,13 +43,11 @@ module SimplyDB
|
|
51
43
|
'Action' => 'PutAttributes'
|
52
44
|
})
|
53
45
|
call(params) do |doc|
|
54
|
-
|
55
|
-
block.call(ret_val) if block_given?
|
56
|
-
ret_val
|
46
|
+
doc.css("PutAttributesResponse").length > 0
|
57
47
|
end
|
58
48
|
end
|
59
|
-
|
60
|
-
def batch_put_attributes(name, items = {}
|
49
|
+
|
50
|
+
def batch_put_attributes(name, items = {})
|
61
51
|
params = {'DomainName' => name, 'ActionName' => 'BatchPutAttributes'}
|
62
52
|
items.keys.each_with_index do |key, i|
|
63
53
|
params["Item.#{i}.ItemName"] = key
|
@@ -72,13 +62,11 @@ module SimplyDB
|
|
72
62
|
end
|
73
63
|
end
|
74
64
|
call(params) do |doc|
|
75
|
-
|
76
|
-
block.call(ret_val) if block_given?
|
77
|
-
ret_val
|
65
|
+
doc.css("BatchPutAttributesResponse").length > 0
|
78
66
|
end
|
79
67
|
end
|
80
|
-
|
81
|
-
def delete_attributes(name, id, attributes = {}, expected = {}
|
68
|
+
|
69
|
+
def delete_attributes(name, id, attributes = {}, expected = {})
|
82
70
|
params = define_attributes(attributes, expected)
|
83
71
|
params.merge!({
|
84
72
|
'DomainName' => name,
|
@@ -86,23 +74,21 @@ module SimplyDB
|
|
86
74
|
'Action' => 'DeleteAttributes'
|
87
75
|
})
|
88
76
|
call(params) do |doc|
|
89
|
-
|
90
|
-
block.call(ret_val) if block_given?
|
91
|
-
ret_val
|
77
|
+
doc.css("DeleteAttributesResponse").length > 0
|
92
78
|
end
|
93
79
|
end
|
94
|
-
|
95
|
-
def get_attributes(name, id, wanted_attributes = [], consistent_read = false
|
80
|
+
|
81
|
+
def get_attributes(name, id, wanted_attributes = [], consistent_read = false)
|
96
82
|
params = {
|
97
83
|
'Action' => 'GetAttributes',
|
98
84
|
'DomainName' => name,
|
99
85
|
'ItemName' => id,
|
100
|
-
'ConsistentRead' => consistent_read.to_s,
|
86
|
+
'ConsistentRead' => consistent_read.to_s,
|
101
87
|
}
|
102
88
|
wanted_attributes.each_with_index {|name, index| params["AttributeName.#{index}"] = name}
|
103
89
|
|
104
90
|
call(params) do |doc|
|
105
|
-
|
91
|
+
doc.css("Attribute").inject({}) do |memo, attribute|
|
106
92
|
name = attribute.css("Name").first.text
|
107
93
|
value = attribute.css("Value").first.text
|
108
94
|
if memo.has_key?(name)
|
@@ -113,12 +99,10 @@ module SimplyDB
|
|
113
99
|
end
|
114
100
|
memo
|
115
101
|
end
|
116
|
-
block.call(attributes) if block_given?
|
117
|
-
attributes
|
118
102
|
end
|
119
103
|
end
|
120
|
-
|
121
|
-
def select(expression, consistent_read = false, next_token = nil
|
104
|
+
|
105
|
+
def select(expression, consistent_read = false, next_token = nil)
|
122
106
|
params = {
|
123
107
|
'Action' => 'Select',
|
124
108
|
'SelectExpression' => expression,
|
@@ -126,9 +110,9 @@ module SimplyDB
|
|
126
110
|
}
|
127
111
|
params['NextToken'] = next_token unless next_token.nil?
|
128
112
|
call(params) do |doc|
|
129
|
-
|
130
|
-
item_name =
|
131
|
-
|
113
|
+
doc.css("SelectResponse SelectResult Item").collect do |element|
|
114
|
+
item_name = element.css("Name").first.text
|
115
|
+
item = element.css("Attribute").inject({}) do |attributes, attribute|
|
132
116
|
attribute_name = attribute.css("Name").first.text
|
133
117
|
attribute_value = attribute.css("Value").first.text
|
134
118
|
if attributes.has_key?(attribute_name)
|
@@ -139,13 +123,11 @@ module SimplyDB
|
|
139
123
|
end
|
140
124
|
attributes
|
141
125
|
end
|
142
|
-
|
126
|
+
{item_name => item}
|
143
127
|
end
|
144
|
-
block.call(ret_val) if block_given?
|
145
|
-
ret_val
|
146
128
|
end
|
147
129
|
end
|
148
|
-
|
130
|
+
|
149
131
|
private
|
150
132
|
def define_attributes(attributes = {}, expected = {}, replace = false)
|
151
133
|
params = {}
|
@@ -154,7 +136,7 @@ module SimplyDB
|
|
154
136
|
v.each do |value|
|
155
137
|
params["Attribute.#{index}.Name"] = k
|
156
138
|
params["Attribute.#{index}.Value"] = value
|
157
|
-
params["Attribute.#{index}.Replace"] = "
|
139
|
+
params["Attribute.#{index}.Replace"] = "true" if replace
|
158
140
|
index += 1
|
159
141
|
end
|
160
142
|
index
|
@@ -178,9 +160,9 @@ module SimplyDB
|
|
178
160
|
end
|
179
161
|
index
|
180
162
|
}
|
181
|
-
|
163
|
+
params
|
182
164
|
end
|
183
|
-
|
165
|
+
|
184
166
|
def call(params = {}, attempts = 3, &block)
|
185
167
|
@client.call(:post, params) do |body|
|
186
168
|
begin
|
@@ -194,7 +176,7 @@ module SimplyDB
|
|
194
176
|
@next_token = doc.css("NextToken").first.text unless doc.css("NextToken").empty?
|
195
177
|
block.call(doc)
|
196
178
|
end
|
197
|
-
rescue SimplyDB::Error::ServiceUnavailable => e
|
179
|
+
rescue SimplyDB::Error::ServiceUnavailable, RestClient::ServiceUnavailable => e
|
198
180
|
if attempts > 0
|
199
181
|
call(params, attempts - 1, &block)
|
200
182
|
else
|