ijin-right_aws 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/History.txt +239 -0
  2. data/Manifest.txt +46 -0
  3. data/README.txt +167 -0
  4. data/Rakefile +125 -0
  5. data/VERSION +1 -0
  6. data/lib/acf/right_acf_interface.rb +413 -0
  7. data/lib/acw/right_acw_interface.rb +249 -0
  8. data/lib/as/right_as_interface.rb +690 -0
  9. data/lib/awsbase/benchmark_fix.rb +39 -0
  10. data/lib/awsbase/right_awsbase.rb +931 -0
  11. data/lib/awsbase/support.rb +115 -0
  12. data/lib/ec2/right_ec2.rb +617 -0
  13. data/lib/ec2/right_ec2_ebs.rb +451 -0
  14. data/lib/ec2/right_ec2_images.rb +373 -0
  15. data/lib/ec2/right_ec2_instances.rb +760 -0
  16. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  17. data/lib/ec2/right_ec2_reserved_instances.rb +167 -0
  18. data/lib/ec2/right_ec2_vpc.rb +571 -0
  19. data/lib/elb/right_elb_interface.rb +407 -0
  20. data/lib/rds/right_rds_interface.rb +998 -0
  21. data/lib/right_aws.rb +79 -0
  22. data/lib/s3/right_s3.rb +1102 -0
  23. data/lib/s3/right_s3_interface.rb +1195 -0
  24. data/lib/sdb/active_sdb.rb +930 -0
  25. data/lib/sdb/right_sdb_interface.rb +672 -0
  26. data/lib/sqs/right_sqs.rb +388 -0
  27. data/lib/sqs/right_sqs_gen2.rb +343 -0
  28. data/lib/sqs/right_sqs_gen2_interface.rb +523 -0
  29. data/lib/sqs/right_sqs_interface.rb +594 -0
  30. data/test/acf/test_helper.rb +2 -0
  31. data/test/acf/test_right_acf.rb +146 -0
  32. data/test/awsbase/test_helper.rb +2 -0
  33. data/test/awsbase/test_right_awsbase.rb +12 -0
  34. data/test/ec2/test_helper.rb +2 -0
  35. data/test/ec2/test_right_ec2.rb +108 -0
  36. data/test/http_connection.rb +87 -0
  37. data/test/rds/test_helper.rb +2 -0
  38. data/test/rds/test_right_rds.rb +120 -0
  39. data/test/s3/test_helper.rb +2 -0
  40. data/test/s3/test_right_s3.rb +419 -0
  41. data/test/s3/test_right_s3_stubbed.rb +95 -0
  42. data/test/sdb/test_active_sdb.rb +299 -0
  43. data/test/sdb/test_helper.rb +3 -0
  44. data/test/sdb/test_right_sdb.rb +247 -0
  45. data/test/sqs/test_helper.rb +2 -0
  46. data/test/sqs/test_right_sqs.rb +291 -0
  47. data/test/sqs/test_right_sqs_gen2.rb +276 -0
  48. data/test/test_credentials.rb +37 -0
  49. data/test/ts_right_aws.rb +14 -0
  50. metadata +122 -0
@@ -0,0 +1,672 @@
1
+ #
2
+ # Copyright (c) 2008 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ require "right_aws"
25
+
26
+ module RightAws
27
+
28
+ class SdbInterface < RightAwsBase
29
+
30
+ include RightAwsBaseInterface
31
+
32
+ DEFAULT_HOST = 'sdb.amazonaws.com'
33
+ DEFAULT_PORT = 443
34
+ DEFAULT_PROTOCOL = 'https'
35
+ DEFAULT_PATH = '/'
36
+ API_VERSION = '2007-11-07'
37
+ DEFAULT_NIL_REPRESENTATION = 'nil'
38
+
39
+ @@bench = AwsBenchmarkingBlock.new
40
+ def self.bench_xml; @@bench.xml; end
41
+ def self.bench_sdb; @@bench.service; end
42
+
43
+ attr_reader :last_query_expression
44
+
45
+ # Creates new RightSdb instance.
46
+ #
47
+ # Params:
48
+ # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
49
+ # :port => 443 # Amazon service port: 80 or 443(default)
50
+ # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
51
+ # :signature_version => '0' # The signature version : '0','1 or '2'(default)
52
+ # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
53
+ # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
54
+ # :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
55
+ #
56
+ # Example:
57
+ #
58
+ # sdb = RightAws::SdbInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX', {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<RightSdb:0xa6b8c27c>
59
+ #
60
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/
61
+ #
62
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
63
+ @nil_rep = params[:nil_representation] ? params[:nil_representation] : DEFAULT_NIL_REPRESENTATION
64
+ params.delete(:nil_representation)
65
+ init({ :name => 'SDB',
66
+ :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
67
+ :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
68
+ :default_service => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).path : DEFAULT_PATH,
69
+ :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL,
70
+ :default_api_version => ENV['SDB_API_VERSION'] || API_VERSION },
71
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
72
+ aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
73
+ params)
74
+ end
75
+
76
+ #-----------------------------------------------------------------
77
+ # Requests
78
+ #-----------------------------------------------------------------
79
+
80
+ def generate_request(action, params={}) #:nodoc:
81
+ generate_request_impl(:get, action, params )
82
+ end
83
+
84
+ # Sends request to Amazon and parses the response
85
+ # Raises AwsError if any banana happened
86
+ def request_info(request, parser) #:nodoc:
87
+ request_info_impl(:sdb_connection, @@bench, request, parser)
88
+ end
89
+
90
+ # Prepare attributes for putting.
91
+ # (used by put_attributes)
92
+ def pack_attributes(attributes, replace = false) #:nodoc:
93
+ result = {}
94
+ if attributes
95
+ idx = 0
96
+ skip_values = attributes.is_a?(Array)
97
+ attributes.each do |attribute, values|
98
+ # set replacement attribute
99
+ result["Attribute.#{idx}.Replace"] = 'true' if replace
100
+ # pack Name/Value
101
+ unless values.nil?
102
+ Array(values).each do |value|
103
+ result["Attribute.#{idx}.Name"] = attribute
104
+ result["Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
105
+ idx += 1
106
+ end
107
+ else
108
+ result["Attribute.#{idx}.Name"] = attribute
109
+ result["Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
110
+ idx += 1
111
+ end
112
+ end
113
+ end
114
+ result
115
+ end
116
+
117
+ # Use this helper to manually escape the fields in the query expressions.
118
+ # To escape the single quotes and backslashes and to wrap the string into the single quotes.
119
+ #
120
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API.html
121
+ #
122
+ def escape(value)
123
+ %Q{'#{value.to_s.gsub(/(['\\])/){ "\\#{$1}" }}'} if value
124
+ end
125
+
126
+ # Convert a Ruby language value to a SDB value by replacing Ruby nil with the user's chosen string representation of nil.
127
+ # Non-nil values are unaffected by this filter.
128
+ def ruby_to_sdb(value)
129
+ value.nil? ? @nil_rep : value
130
+ end
131
+
132
+ # Convert a SDB value to a Ruby language value by replacing the user's chosen string representation of nil with Ruby nil.
133
+ # Values are unaffected by this filter unless they match the nil representation exactly.
134
+ def sdb_to_ruby(value)
135
+ value.eql?(@nil_rep) ? nil : value
136
+ end
137
+
138
+ # Convert select and query_with_attributes responses to a Ruby language values by replacing the user's chosen string representation of nil with Ruby nil.
139
+ # (This method affects on a passed response value)
140
+ def select_response_to_ruby(response) #:nodoc:
141
+ response[:items].each_with_index do |item, idx|
142
+ item.each do |key, attributes|
143
+ attributes.each do |name, values|
144
+ values.collect! { |value| sdb_to_ruby(value) }
145
+ end
146
+ end
147
+ end
148
+ response
149
+ end
150
+
151
+ # Create query expression from an array.
152
+ # (similar to ActiveRecord::Base#find using :conditions => ['query', param1, .., paramN])
153
+ #
154
+ def query_expression_from_array(params) #:nodoc:
155
+ return '' if params.blank?
156
+ query = params.shift.to_s
157
+ query.gsub(/(\\)?(\?)/) do
158
+ if $1 # if escaped '\?' is found - replace it by '?' without backslash
159
+ "?"
160
+ else # well, if no backslash precedes '?' then replace it by next param from the list
161
+ escape(params.shift)
162
+ end
163
+ end
164
+ end
165
+
166
+ def query_expression_from_hash(hash)
167
+ return '' if hash.blank?
168
+ expression = []
169
+ hash.each do |key, value|
170
+ expression << "#{key}=#{escape(value)}"
171
+ end
172
+ expression.join(' AND ')
173
+ end
174
+
175
+ # Retrieve a list of SDB domains from Amazon.
176
+ #
177
+ # Returns a hash:
178
+ # { :domains => [domain1, ..., domainN],
179
+ # :next_token => string || nil,
180
+ # :box_usage => string,
181
+ # :request_id => string }
182
+ #
183
+ # Example:
184
+ #
185
+ # sdb = RightAws::SdbInterface.new
186
+ # sdb.list_domains #=> { :box_usage => "0.0000071759",
187
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982",
188
+ # :domains => ["toys", "dolls"]}
189
+ #
190
+ # If a block is given, this method yields to it. If the block returns true, list_domains will continue looping the request. If the block returns false,
191
+ # list_domains will end.
192
+ #
193
+ # sdb.list_domains(10) do |result| # list by 10 domains per iteration
194
+ # puts result.inspect
195
+ # true
196
+ # end
197
+ #
198
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_ListDomains.html
199
+ #
200
+ def list_domains(max_number_of_domains = nil, next_token = nil )
201
+ request_params = { 'MaxNumberOfDomains' => max_number_of_domains,
202
+ 'NextToken' => next_token }
203
+ link = generate_request("ListDomains", request_params)
204
+ result = request_info(link, QSdbListDomainParser.new)
205
+ # return result if no block given
206
+ return result unless block_given?
207
+ # loop if block if given
208
+ begin
209
+ # the block must return true if it wanna continue
210
+ break unless yield(result) && result[:next_token]
211
+ # make new request
212
+ request_params['NextToken'] = result[:next_token]
213
+ link = generate_request("ListDomains", request_params)
214
+ result = request_info(link, QSdbListDomainParser.new)
215
+ end while true
216
+ rescue Exception
217
+ on_exception
218
+ end
219
+
220
+ # Create new SDB domain at Amazon.
221
+ #
222
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
223
+ # (Amazon raises no errors if the domain already exists).
224
+ #
225
+ # Example:
226
+ #
227
+ # sdb = RightAws::SdbInterface.new
228
+ # sdb.create_domain('toys') # => { :box_usage => "0.0000071759",
229
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982" }
230
+ #
231
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_CreateDomain.html
232
+ def create_domain(domain_name)
233
+ link = generate_request("CreateDomain",
234
+ 'DomainName' => domain_name)
235
+ request_info(link, QSdbSimpleParser.new)
236
+ rescue Exception
237
+ on_exception
238
+ end
239
+
240
+ # Delete SDB domain at Amazon.
241
+ #
242
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
243
+ # (Amazon raises no errors if the domain does not exist).
244
+ #
245
+ # Example:
246
+ #
247
+ # sdb = RightAws::SdbInterface.new
248
+ # sdb.delete_domain('toys') # => { :box_usage => "0.0000071759",
249
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982" }
250
+ #
251
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_DeleteDomain.html
252
+ #
253
+ def delete_domain(domain_name)
254
+ link = generate_request("DeleteDomain",
255
+ 'DomainName' => domain_name)
256
+ request_info(link, QSdbSimpleParser.new)
257
+ rescue Exception
258
+ on_exception
259
+ end
260
+
261
+ # Add/Replace item attributes.
262
+ #
263
+ # Params:
264
+ # domain_name = DomainName
265
+ # item_name = ItemName
266
+ # attributes = {
267
+ # 'nameA' => [valueA1,..., valueAN],
268
+ # ...
269
+ # 'nameZ' => [valueZ1,..., valueZN]
270
+ # }
271
+ # replace = :replace | any other value to skip replacement
272
+ #
273
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
274
+ # (Amazon raises no errors if the attribute was not overridden, as when the :replace param is unset).
275
+ #
276
+ # Example:
277
+ #
278
+ # sdb = RightAws::SdbInterface.new
279
+ # sdb.create_domain 'family'
280
+ #
281
+ # attributes = {}
282
+ # # create attributes for Jon and Silvia
283
+ # attributes['Jon'] = %w{ car beer }
284
+ # attributes['Silvia'] = %w{ beetle rolling_pin kids }
285
+ # sdb.put_attributes 'family', 'toys', attributes #=> ok
286
+ # # now: Jon=>[car, beer], Silvia=>[beetle, rolling_pin, kids]
287
+ #
288
+ # # add attributes to Jon
289
+ # attributes.delete('Silvia')
290
+ # attributes['Jon'] = %w{ girls pub }
291
+ # sdb.put_attributes 'family', 'toys', attributes #=> ok
292
+ # # now: Jon=>[car, beer, girls, pub], Silvia=>[beetle, rolling_pin, kids]
293
+ #
294
+ # # replace attributes for Jon and add to a cat (the cat had no attributes before)
295
+ # attributes['Jon'] = %w{ vacuum_cleaner hammer spade }
296
+ # attributes['cat'] = %w{ mouse clew Jons_socks }
297
+ # sdb.put_attributes 'family', 'toys', attributes, :replace #=> ok
298
+ # # now: Jon=>[vacuum_cleaner, hammer, spade], Silvia=>[beetle, rolling_pin, kids], cat=>[mouse, clew, Jons_socks]
299
+ #
300
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_PutAttributes.html
301
+ #
302
+ def put_attributes(domain_name, item_name, attributes, replace = false)
303
+ params = { 'DomainName' => domain_name,
304
+ 'ItemName' => item_name }.merge(pack_attributes(attributes, replace))
305
+ link = generate_request("PutAttributes", params)
306
+ request_info( link, QSdbSimpleParser.new )
307
+ rescue Exception
308
+ on_exception
309
+ end
310
+
311
+ # Retrieve SDB item's attribute(s).
312
+ #
313
+ # Returns a hash:
314
+ # { :box_usage => string,
315
+ # :request_id => string,
316
+ # :attributes => { 'nameA' => [valueA1,..., valueAN],
317
+ # ... ,
318
+ # 'nameZ' => [valueZ1,..., valueZN] } }
319
+ #
320
+ # Example:
321
+ # # request all attributes
322
+ # sdb.get_attributes('family', 'toys') # => { :attributes => {"cat" => ["clew", "Jons_socks", "mouse"] },
323
+ # "Silvia" => ["beetle", "rolling_pin", "kids"],
324
+ # "Jon" => ["vacuum_cleaner", "hammer", "spade"]},
325
+ # :box_usage => "0.0000093222",
326
+ # :request_id => "81273d21-000-1111-b3f9-512d91d29ac8" }
327
+ #
328
+ # # request cat's attributes only
329
+ # sdb.get_attributes('family', 'toys', 'cat') # => { :attributes => {"cat" => ["clew", "Jons_socks", "mouse"] },
330
+ # :box_usage => "0.0000093222",
331
+ # :request_id => "81273d21-001-1111-b3f9-512d91d29ac8" }
332
+ #
333
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_GetAttributes.html
334
+ #
335
+ def get_attributes(domain_name, item_name, attribute_name=nil)
336
+ link = generate_request("GetAttributes", 'DomainName' => domain_name,
337
+ 'ItemName' => item_name,
338
+ 'AttributeName' => attribute_name )
339
+ res = request_info(link, QSdbGetAttributesParser.new)
340
+ res[:attributes].each_value do |values|
341
+ values.collect! { |e| sdb_to_ruby(e) }
342
+ end
343
+ res
344
+ rescue Exception
345
+ on_exception
346
+ end
347
+
348
+ # Delete value, attribute or item.
349
+ #
350
+ # Example:
351
+ # # delete 'vodka' and 'girls' from 'Jon' and 'mice' from 'cat'.
352
+ # sdb.delete_attributes 'family', 'toys', { 'Jon' => ['vodka', 'girls'], 'cat' => ['mice'] }
353
+ #
354
+ # # delete the all the values from attributes (i.e. delete the attributes)
355
+ # sdb.delete_attributes 'family', 'toys', { 'Jon' => [], 'cat' => [] }
356
+ # # or
357
+ # sdb.delete_attributes 'family', 'toys', [ 'Jon', 'cat' ]
358
+ #
359
+ # # delete all the attributes from item 'toys' (i.e. delete the item)
360
+ # sdb.delete_attributes 'family', 'toys'
361
+ #
362
+ # see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_DeleteAttributes.html
363
+ #
364
+ def delete_attributes(domain_name, item_name, attributes = nil)
365
+ params = { 'DomainName' => domain_name,
366
+ 'ItemName' => item_name }.merge(pack_attributes(attributes))
367
+ link = generate_request("DeleteAttributes", params)
368
+ request_info( link, QSdbSimpleParser.new )
369
+ rescue Exception
370
+ on_exception
371
+ end
372
+
373
+
374
+ # QUERY:
375
+
376
+ # Perform a query on SDB.
377
+ #
378
+ # Returns a hash:
379
+ # { :box_usage => string,
380
+ # :request_id => string,
381
+ # :next_token => string,
382
+ # :items => [ItemName1,..., ItemNameN] }
383
+ #
384
+ # Example:
385
+ #
386
+ # query = "['cat' = 'clew']"
387
+ # sdb.query('family', query) #=> hash of data
388
+ # sdb.query('family', query, 10) #=> hash of data with max of 10 items
389
+ #
390
+ # If a block is given, query will iteratively yield results to it as long as the block continues to return true.
391
+ #
392
+ # # List 10 items per iteration. Don't
393
+ # # forget to escape single quotes and backslashes and wrap all the items in single quotes.
394
+ # query = "['cat'='clew'] union ['dog'='Jon\\'s boot']"
395
+ # sdb.query('family', query, 10) do |result|
396
+ # puts result.inspect
397
+ # true
398
+ # end
399
+ #
400
+ # # Same query using automatic escaping...to use the auto escape, pass the query and its params as an array:
401
+ # query = [ "['cat'=?] union ['dog'=?]", "clew", "Jon's boot" ]
402
+ # sdb.query('family', query)
403
+ #
404
+ # query = [ "['cat'=?] union ['dog'=?] sort 'cat' desc", "clew", "Jon's boot" ]
405
+ # sdb.query('family', query)
406
+ #
407
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_Query.html
408
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SortingData.html
409
+ #
410
+ def query(domain_name, query_expression = nil, max_number_of_items = nil, next_token = nil)
411
+ query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
412
+ @last_query_expression = query_expression
413
+ #
414
+ request_params = { 'DomainName' => domain_name,
415
+ 'QueryExpression' => query_expression,
416
+ 'MaxNumberOfItems' => max_number_of_items,
417
+ 'NextToken' => next_token }
418
+ link = generate_request("Query", request_params)
419
+ result = request_info( link, QSdbQueryParser.new )
420
+ # return result if no block given
421
+ return result unless block_given?
422
+ # loop if block if given
423
+ begin
424
+ # the block must return true if it wanna continue
425
+ break unless yield(result) && result[:next_token]
426
+ # make new request
427
+ request_params['NextToken'] = result[:next_token]
428
+ link = generate_request("Query", request_params)
429
+ result = request_info( link, QSdbQueryParser.new )
430
+ end while true
431
+ rescue Exception
432
+ on_exception
433
+ end
434
+
435
+ # Perform a query and fetch specified attributes.
436
+ # If attributes are not specified then fetches the whole list of attributes.
437
+ #
438
+ #
439
+ # Returns a hash:
440
+ # { :box_usage => string,
441
+ # :request_id => string,
442
+ # :next_token => string,
443
+ # :items => [ { ItemName1 => { attribute1 => value1, ... attributeM => valueM } },
444
+ # { ItemName2 => {...}}, ... ]
445
+ #
446
+ # Example:
447
+ #
448
+ # sdb.query_with_attributes(domain, ['hobby', 'country'], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
449
+ # { :request_id => "06057228-70d0-4487-89fb-fd9c028580d3",
450
+ # :items =>
451
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
452
+ # { "hobby" => ["cooking", "flowers", "cats"],
453
+ # "country" => ["Russia"]}},
454
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
455
+ # { "hobby" => ["patchwork", "bundle jumping"],
456
+ # "country" => ["USA"]}}, ... ],
457
+ # :box_usage=>"0.0000504786"}
458
+ #
459
+ # sdb.query_with_attributes(domain, [], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
460
+ # { :request_id => "75bb19db-a529-4f69-b86f-5e3800f79a45",
461
+ # :items =>
462
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
463
+ # { "hobby" => ["cooking", "flowers", "cats"],
464
+ # "name" => ["Mary"],
465
+ # "country" => ["Russia"],
466
+ # "gender" => ["female"],
467
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
468
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
469
+ # { "hobby" => ["patchwork", "bundle jumping"],
470
+ # "name" => ["Mary"],
471
+ # "country" => ["USA"],
472
+ # "gender" => ["female"],
473
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ],
474
+ # :box_usage=>"0.0000506668"}
475
+ #
476
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_QueryWithAttributes.html
477
+ #
478
+ def query_with_attributes(domain_name, attributes=[], query_expression = nil, max_number_of_items = nil, next_token = nil)
479
+ attributes = attributes.to_a
480
+ query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
481
+ @last_query_expression = query_expression
482
+ #
483
+ request_params = { 'DomainName' => domain_name,
484
+ 'QueryExpression' => query_expression,
485
+ 'MaxNumberOfItems' => max_number_of_items,
486
+ 'NextToken' => next_token }
487
+ attributes.each_with_index do |attribute, idx|
488
+ request_params["AttributeName.#{idx+1}"] = attribute
489
+ end
490
+ link = generate_request("QueryWithAttributes", request_params)
491
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
492
+ # return result if no block given
493
+ return result unless block_given?
494
+ # loop if block if given
495
+ begin
496
+ # the block must return true if it wanna continue
497
+ break unless yield(result) && result[:next_token]
498
+ # make new request
499
+ request_params['NextToken'] = result[:next_token]
500
+ link = generate_request("QueryWithAttributes", request_params)
501
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
502
+ end while true
503
+ rescue Exception
504
+ on_exception
505
+ end
506
+
507
+ # Perform SQL-like select and fetch attributes.
508
+ # Attribute values must be quoted with a single or double quote. If a quote appears within the attribute value, it must be escaped with the same quote symbol as shown in the following example.
509
+ # (Use array to pass select_expression params to avoid manual escaping).
510
+ #
511
+ # sdb.select(["select * from my_domain where gender=?", 'female']) #=>
512
+ # {:request_id =>"8241b843-0fb9-4d66-9100-effae12249ec",
513
+ # :items =>
514
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
515
+ # {"hobby" => ["cooking", "flowers", "cats"],
516
+ # "name" => ["Mary"],
517
+ # "country" => ["Russia"],
518
+ # "gender" => ["female"],
519
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
520
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
521
+ # {"hobby" => ["patchwork", "bundle jumping"],
522
+ # "name" => ["Mary"],
523
+ # "country" => ["USA"],
524
+ # "gender" => ["female"],
525
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ]
526
+ # :box_usage =>"0.0000506197"}
527
+ #
528
+ # sdb.select('select country, name from my_domain') #=>
529
+ # {:request_id=>"b1600198-c317-413f-a8dc-4e7f864a940a",
530
+ # :items=>
531
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
532
+ # { "376d2e00-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Putin"], "country"=>["Russia"]} },
533
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} },
534
+ # { "372ebbd4-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Bush"], "country"=>["USA"]} },
535
+ # { "37a4e552-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Medvedev"], "country"=>["Russia"]} },
536
+ # { "38278dfe-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
537
+ # { "37df6c36-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} } ],
538
+ # :box_usage=>"0.0000777663"}
539
+ #
540
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_Select.html
541
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingSelect.html
542
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDBLimits.html
543
+ #
544
+ def select(select_expression, next_token = nil)
545
+ select_expression = query_expression_from_array(select_expression) if select_expression.is_a?(Array)
546
+ @last_query_expression = select_expression
547
+ #
548
+ request_params = { 'SelectExpression' => select_expression,
549
+ 'NextToken' => next_token }
550
+ link = generate_request("Select", request_params)
551
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
552
+ return result unless block_given?
553
+ # loop if block if given
554
+ begin
555
+ # the block must return true if it wanna continue
556
+ break unless yield(result) && result[:next_token]
557
+ # make new request
558
+ request_params['NextToken'] = result[:next_token]
559
+ link = generate_request("Select", request_params)
560
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
561
+ end while true
562
+ rescue Exception
563
+ on_exception
564
+ end
565
+
566
+ #-----------------------------------------------------------------
567
+ # PARSERS:
568
+ #-----------------------------------------------------------------
569
+ class QSdbListDomainParser < RightAWSParser #:nodoc:
570
+ def reset
571
+ @result = { :domains => [] }
572
+ end
573
+ def tagend(name)
574
+ case name
575
+ when 'NextToken' then @result[:next_token] = @text
576
+ when 'DomainName' then @result[:domains] << @text
577
+ when 'BoxUsage' then @result[:box_usage] = @text
578
+ when 'RequestId' then @result[:request_id] = @text
579
+ end
580
+ end
581
+ end
582
+
583
+ class QSdbSimpleParser < RightAWSParser #:nodoc:
584
+ def reset
585
+ @result = {}
586
+ end
587
+ def tagend(name)
588
+ case name
589
+ when 'BoxUsage' then @result[:box_usage] = @text
590
+ when 'RequestId' then @result[:request_id] = @text
591
+ end
592
+ end
593
+ end
594
+
595
+ class QSdbGetAttributesParser < RightAWSParser #:nodoc:
596
+ def reset
597
+ @last_attribute_name = nil
598
+ @result = { :attributes => {} }
599
+ end
600
+ def tagend(name)
601
+ case name
602
+ when 'Name' then @last_attribute_name = @text
603
+ when 'Value' then (@result[:attributes][@last_attribute_name] ||= []) << @text
604
+ when 'BoxUsage' then @result[:box_usage] = @text
605
+ when 'RequestId' then @result[:request_id] = @text
606
+ end
607
+ end
608
+ end
609
+
610
+ class QSdbQueryParser < RightAWSParser #:nodoc:
611
+ def reset
612
+ @result = { :items => [] }
613
+ end
614
+ def tagend(name)
615
+ case name
616
+ when 'ItemName' then @result[:items] << @text
617
+ when 'BoxUsage' then @result[:box_usage] = @text
618
+ when 'RequestId' then @result[:request_id] = @text
619
+ when 'NextToken' then @result[:next_token] = @text
620
+ end
621
+ end
622
+ end
623
+
624
+ class QSdbQueryWithAttributesParser < RightAWSParser #:nodoc:
625
+ def reset
626
+ @result = { :items => [] }
627
+ end
628
+ def tagend(name)
629
+ case name
630
+ when 'Name'
631
+ case @xmlpath
632
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item'
633
+ @item = @text
634
+ @result[:items] << { @item => {} }
635
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item/Attribute'
636
+ @attribute = @text
637
+ @result[:items].last[@item][@attribute] ||= []
638
+ end
639
+ when 'RequestId' then @result[:request_id] = @text
640
+ when 'BoxUsage' then @result[:box_usage] = @text
641
+ when 'NextToken' then @result[:next_token] = @text
642
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
643
+ end
644
+ end
645
+ end
646
+
647
+ class QSdbSelectParser < RightAWSParser #:nodoc:
648
+ def reset
649
+ @result = { :items => [] }
650
+ end
651
+ def tagend(name)
652
+ case name
653
+ when 'Name'
654
+ case @xmlpath
655
+ when 'SelectResponse/SelectResult/Item'
656
+ @item = @text
657
+ @result[:items] << { @item => {} }
658
+ when 'SelectResponse/SelectResult/Item/Attribute'
659
+ @attribute = @text
660
+ @result[:items].last[@item][@attribute] ||= []
661
+ end
662
+ when 'RequestId' then @result[:request_id] = @text
663
+ when 'BoxUsage' then @result[:box_usage] = @text
664
+ when 'NextToken' then @result[:next_token] = @text
665
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
666
+ end
667
+ end
668
+ end
669
+
670
+ end
671
+
672
+ end