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 CHANGED
@@ -1,21 +1,5 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
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
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simplydb.gemspec
4
+ gemspec
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 'rubygems'
2
- require 'rake'
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
3
 
4
- begin
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
- task :spec => :check_dependencies
37
-
38
- task :default => :spec
39
-
40
- desc "irb loaded with SimplyDB (rubygems not required)"
41
- task :irb do
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
- require 'rake/rdoctask'
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
@@ -1,5 +1,4 @@
1
- require 'rubygems'
2
- require 'simplydb/extensions'
3
1
  require 'simplydb/error'
2
+ require 'simplydb/interface'
4
3
  require 'simplydb/client'
5
- require 'simplydb/interface'
4
+ require 'simplydb/server'
@@ -1,66 +1,79 @@
1
1
  require 'openssl'
2
2
  require 'digest/sha1'
3
3
  require 'base64'
4
- require 'uri'
5
- require 'simplydb/clients/typhoeus'
4
+ require 'rest_client'
6
5
 
7
6
  module SimplyDB
8
7
  class Client
9
- include SimplyDB::Extensions
10
-
11
- attr_accessor :options, :http_client
12
-
13
- def initialize(options = {})
14
- @options = {
15
- :async => false,
16
- :protocol => 'https://',
17
- :host => 'sdb.amazonaws.com',
18
- :port => 443,
19
- :path => "/",
20
- :signature_version => '2',
21
- :version => '2009-04-15',
22
- :signature_method => 'HmacSHA256',
23
- }.merge(options)
24
- @http_client = (@options[:client] || SimplyDB::Clients::Typhoeus).new(options)
25
- end
26
-
27
- def async?
28
- return options[:async] == true
29
- end
30
-
31
- def base_url
32
- "#{@options[:protocol]}#{@options[:host]}:#{@options[:port]}#{@options[:path]}"
33
- end
34
-
35
- def string_to_sign(method, params)
36
- return "#{method.to_s.upcase}\n#{options[:host]}\n/\n" + escape_hash(params)
37
- end
38
-
39
- def generate_signature(method, params)
40
- Base64.encode64(
41
- OpenSSL::HMAC.digest(
42
- OpenSSL::Digest::Digest.new('sha256'),
43
- @options[:secret_key],
44
- string_to_sign(method, params)
45
- )
46
- ).chomp
47
- end
48
-
49
- def params_with_signature(method, params)
50
- params.merge!({
51
- 'AWSAccessKeyId' => @options[:access_key],
52
- 'SignatureVersion' => @options[:signature_version],
53
- 'Timestamp' => Time.now.iso8601,
54
- 'Version' => @options[:version],
55
- 'SignatureMethod' => @options[:signature_method]
56
- })
57
- params['Signature'] = generate_signature(method, params)
58
- return params
59
- end
60
-
61
- def call(method, params ={}, &on_complete)
62
- options = {:method => method, :url => base_url, :params => params_with_signature(method, params)}
63
- @http_client.request(options, !async?) {|request| on_complete.call(request.body)}
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
@@ -1,60 +1,65 @@
1
1
  module SimplyDB
2
- module Error
3
- # ref http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/APIError.html
4
- class AccessFailure < RuntimeError; end
5
- class AttributeDoesNotExist < RuntimeError; end
6
- class AuthFailure < RuntimeError; end
7
- class AuthMissingFailure < RuntimeError; end
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
@@ -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, &block)
10
+
11
+ def create_domain(name)
12
12
  call({'Action' => 'CreateDomain', 'DomainName' => name}) do |doc|
13
- ret_val = doc.css("CreateDomainResponse").length > 0
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, &block)
16
+
17
+ def delete_domain(name)
20
18
  call({'Action' => 'DeleteDomain', 'DomainName' => name}) do |doc|
21
- ret_val = doc.css("DeleteDomainResponse").length > 0
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(&block)
22
+
23
+ def list_domains
28
24
  call({'Action' => 'ListDomains'}) do |doc|
29
- domains = doc.css('DomainName').collect{|d| d.text}
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, &block)
28
+
29
+ def domain_metadata(name)
36
30
  call({'Action' => 'DomainMetadata','DomainName' => name}) do |doc|
37
- attributes = doc.css("DomainMetadataResult").first.children.inject({}) do |memo, child|
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, &block)
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
- ret_val = doc.css("PutAttributesResponse").length > 0
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 = {}, &block)
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
- ret_val = doc.css("BatchPutAttributesResponse").length > 0
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 = {}, &block)
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
- ret_val = doc.css("DeleteAttributesResponse").length > 0
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, &block)
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
- attributes = doc.css("Attribute").inject({}) do |memo, attribute|
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, &block)
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
- ret_val = doc.css("SelectResponse SelectResult Item").inject({}) do |items, item|
130
- item_name = item.css("Name").first.text
131
- items[item_name] = item.css("Attribute").inject({}) do |attributes, attribute|
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
- items
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"] = "1" if 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
- return params
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