right_aws 1.9.0 → 3.1.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 (70) hide show
  1. data/History.txt +164 -13
  2. data/Manifest.txt +28 -1
  3. data/README.txt +12 -10
  4. data/Rakefile +56 -29
  5. data/lib/acf/right_acf_interface.rb +343 -172
  6. data/lib/acf/right_acf_invalidations.rb +144 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  8. data/lib/acf/right_acf_streaming_interface.rb +229 -0
  9. data/lib/acw/right_acw_interface.rb +248 -0
  10. data/lib/as/right_as_interface.rb +698 -0
  11. data/lib/awsbase/right_awsbase.rb +755 -115
  12. data/lib/awsbase/support.rb +2 -78
  13. data/lib/awsbase/version.rb +9 -0
  14. data/lib/ec2/right_ec2.rb +274 -1294
  15. data/lib/ec2/right_ec2_ebs.rb +514 -0
  16. data/lib/ec2/right_ec2_images.rb +444 -0
  17. data/lib/ec2/right_ec2_instances.rb +797 -0
  18. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  19. data/lib/ec2/right_ec2_placement_groups.rb +108 -0
  20. data/lib/ec2/right_ec2_reserved_instances.rb +243 -0
  21. data/lib/ec2/right_ec2_security_groups.rb +496 -0
  22. data/lib/ec2/right_ec2_spot_instances.rb +422 -0
  23. data/lib/ec2/right_ec2_tags.rb +139 -0
  24. data/lib/ec2/right_ec2_vpc.rb +598 -0
  25. data/lib/ec2/right_ec2_vpc2.rb +382 -0
  26. data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
  27. data/lib/elb/right_elb_interface.rb +573 -0
  28. data/lib/emr/right_emr_interface.rb +728 -0
  29. data/lib/iam/right_iam_access_keys.rb +71 -0
  30. data/lib/iam/right_iam_groups.rb +195 -0
  31. data/lib/iam/right_iam_interface.rb +341 -0
  32. data/lib/iam/right_iam_mfa_devices.rb +67 -0
  33. data/lib/iam/right_iam_users.rb +251 -0
  34. data/lib/rds/right_rds_interface.rb +1657 -0
  35. data/lib/right_aws.rb +30 -13
  36. data/lib/route_53/right_route_53_interface.rb +641 -0
  37. data/lib/s3/right_s3.rb +108 -41
  38. data/lib/s3/right_s3_interface.rb +349 -118
  39. data/lib/sdb/active_sdb.rb +388 -54
  40. data/lib/sdb/right_sdb_interface.rb +323 -64
  41. data/lib/sns/right_sns_interface.rb +286 -0
  42. data/lib/sqs/right_sqs.rb +1 -2
  43. data/lib/sqs/right_sqs_gen2.rb +73 -17
  44. data/lib/sqs/right_sqs_gen2_interface.rb +146 -73
  45. data/lib/sqs/right_sqs_interface.rb +12 -22
  46. data/right_aws.gemspec +91 -0
  47. data/test/README.mdown +39 -0
  48. data/test/acf/test_right_acf.rb +11 -19
  49. data/test/awsbase/test_helper.rb +2 -0
  50. data/test/awsbase/test_right_awsbase.rb +11 -0
  51. data/test/ec2/test_right_ec2.rb +32 -1
  52. data/test/elb/test_helper.rb +2 -0
  53. data/test/elb/test_right_elb.rb +43 -0
  54. data/test/rds/test_helper.rb +2 -0
  55. data/test/rds/test_right_rds.rb +120 -0
  56. data/test/route_53/fixtures/a_record.xml +18 -0
  57. data/test/route_53/fixtures/alias_record.xml +18 -0
  58. data/test/route_53/test_helper.rb +2 -0
  59. data/test/route_53/test_right_route_53.rb +141 -0
  60. data/test/s3/test_right_s3.rb +176 -42
  61. data/test/s3/test_right_s3_stubbed.rb +6 -4
  62. data/test/sdb/test_active_sdb.rb +120 -19
  63. data/test/sdb/test_batch_put_attributes.rb +54 -0
  64. data/test/sdb/test_right_sdb.rb +71 -16
  65. data/test/sns/test_helper.rb +2 -0
  66. data/test/sns/test_right_sns.rb +153 -0
  67. data/test/sqs/test_right_sqs.rb +0 -6
  68. data/test/sqs/test_right_sqs_gen2.rb +104 -49
  69. data/test/ts_right_aws.rb +1 -0
  70. metadata +181 -22
@@ -32,7 +32,8 @@ module RightAws
32
32
  DEFAULT_HOST = 'sdb.amazonaws.com'
33
33
  DEFAULT_PORT = 443
34
34
  DEFAULT_PROTOCOL = 'https'
35
- API_VERSION = '2007-11-07'
35
+ DEFAULT_PATH = '/'
36
+ API_VERSION = '2009-04-15'
36
37
  DEFAULT_NIL_REPRESENTATION = 'nil'
37
38
 
38
39
  @@bench = AwsBenchmarkingBlock.new
@@ -47,24 +48,25 @@ module RightAws
47
48
  # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
48
49
  # :port => 443 # Amazon service port: 80 or 443(default)
49
50
  # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
50
- # :signature_version => '0' # The signature version : '0' or '1'(default)
51
- # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
51
+ # :signature_version => '0' # The signature version : '0','1 or '2'(default)
52
52
  # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
53
53
  # :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')
54
54
  #
55
55
  # Example:
56
56
  #
57
- # sdb = RightAws::SdbInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX', {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<RightSdb:0xa6b8c27c>
57
+ # sdb = RightAws::SdbInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX', {:logger => Logger.new('/tmp/x.log')}) #=> #<RightSdb:0xa6b8c27c>
58
58
  #
59
59
  # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/
60
60
  #
61
61
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
62
62
  @nil_rep = params[:nil_representation] ? params[:nil_representation] : DEFAULT_NIL_REPRESENTATION
63
63
  params.delete(:nil_representation)
64
- init({ :name => 'SDB',
65
- :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
66
- :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
67
- :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL },
64
+ init({ :name => 'SDB',
65
+ :default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
66
+ :default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
67
+ :default_service => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).path : DEFAULT_PATH,
68
+ :default_protocol => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).scheme : DEFAULT_PROTOCOL,
69
+ :default_api_version => ENV['SDB_API_VERSION'] || API_VERSION },
68
70
  aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
69
71
  aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
70
72
  params)
@@ -73,69 +75,55 @@ module RightAws
73
75
  #-----------------------------------------------------------------
74
76
  # Requests
75
77
  #-----------------------------------------------------------------
78
+
76
79
  def generate_request(action, params={}) #:nodoc:
77
- # remove empty params from request
78
- params.delete_if {|key,value| value.nil? }
79
- #params_string = params.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
80
- # prepare service data
81
- service_hash = {"Action" => action,
82
- "AWSAccessKeyId" => @aws_access_key_id,
83
- "Version" => API_VERSION,
84
- "Timestamp" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
85
- "SignatureVersion" => signature_version }
86
- service_hash.update(params)
87
- # prepare string to sight
88
- string_to_sign = case signature_version
89
- when '0' then service_hash["Action"] + service_hash["Timestamp"]
90
- when '1' then service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
91
- end
92
- service_hash.update('Signature' => AwsUtils::sign(@aws_secret_access_key, string_to_sign))
93
- service_string = service_hash.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
94
- #
95
- # use POST method if the length of the query string is too large
96
- # see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/MakingRESTRequests.html
97
- if service_string.size > 2000
98
- request = Net::HTTP::Post.new("/")
99
- request.body = service_string
100
- else
101
- #params_string = "&#{params_string}" unless params_string.blank?
102
- request = Net::HTTP::Get.new("/?#{service_string}")
103
- end
104
- # prepare output hash
105
- { :request => request,
106
- :server => @params[:server],
107
- :port => @params[:port],
108
- :protocol => @params[:protocol] }
80
+ generate_request_impl(:get, action, params )
109
81
  end
110
82
 
111
83
  # Sends request to Amazon and parses the response
112
84
  # Raises AwsError if any banana happened
113
85
  def request_info(request, parser) #:nodoc:
114
- thread = @params[:multi_thread] ? Thread.current : Thread.main
115
- thread[:sdb_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
116
- request_info_impl(thread[:sdb_connection], @@bench, request, parser)
86
+ request_info_impl(:sdb_connection, @@bench, request, parser)
117
87
  end
118
88
 
119
89
  # Prepare attributes for putting.
120
90
  # (used by put_attributes)
121
- def pack_attributes(attributes, replace = false) #:nodoc:
91
+ def pack_attributes(items_or_attributes, replace = false, batch = false) #:nodoc:
92
+ if batch
93
+ index = 0
94
+ items_or_attributes.inject({}){|result, (item_name, attributes)|
95
+ item_prefix = "Item.#{index}."
96
+ result["#{item_prefix}ItemName"] = item_name.to_s
97
+ result.merge!(
98
+ pack_single_item_attributes(attributes, replace, item_prefix))
99
+ index += 1
100
+ result
101
+ }
102
+ else
103
+ pack_single_item_attributes(items_or_attributes, replace)
104
+ end
105
+ end
106
+
107
+ def pack_single_item_attributes(attributes, replace, prefix = "")
122
108
  result = {}
123
109
  if attributes
124
110
  idx = 0
125
111
  skip_values = attributes.is_a?(Array)
126
112
  attributes.each do |attribute, values|
127
113
  # set replacement attribute
128
- result["Attribute.#{idx}.Replace"] = 'true' if replace
114
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
129
115
  # pack Name/Value
130
116
  unless values.nil?
131
- Array(values).each do |value|
132
- result["Attribute.#{idx}.Name"] = attribute
133
- result["Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
117
+ # Array(values) does not work here:
118
+ # - Array('') => [] but we wanna get here ['']
119
+ [values].flatten.each do |value|
120
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
121
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
134
122
  idx += 1
135
123
  end
136
124
  else
137
- result["Attribute.#{idx}.Name"] = attribute
138
- result["Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
125
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
126
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
139
127
  idx += 1
140
128
  end
141
129
  end
@@ -163,23 +151,44 @@ module RightAws
163
151
  def sdb_to_ruby(value)
164
152
  value.eql?(@nil_rep) ? nil : value
165
153
  end
166
-
154
+
155
+ # 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.
156
+ # (This method affects on a passed response value)
157
+ def select_response_to_ruby(response) #:nodoc:
158
+ response[:items].each_with_index do |item, idx|
159
+ item.each do |key, attributes|
160
+ attributes.each do |name, values|
161
+ values.collect! { |value| sdb_to_ruby(value) }
162
+ end
163
+ end
164
+ end
165
+ response
166
+ end
167
+
167
168
  # Create query expression from an array.
168
169
  # (similar to ActiveRecord::Base#find using :conditions => ['query', param1, .., paramN])
169
170
  #
170
171
  def query_expression_from_array(params) #:nodoc:
171
- unless params.blank?
172
- query = params.shift.to_s
173
- query.gsub(/(\\)?(\?)/) do
174
- if $1 # if escaped '\?' is found - replace it by '?' without backslash
175
- "?"
176
- else # well, if no backslash precedes '?' then replace it by next param from the list
177
- escape(params.shift)
178
- end
172
+ return '' if params.right_blank?
173
+ query = params.shift.to_s
174
+ query.gsub(/(\\)?(\?)/) do
175
+ if $1 # if escaped '\?' is found - replace it by '?' without backslash
176
+ "?"
177
+ else # well, if no backslash precedes '?' then replace it by next param from the list
178
+ escape(params.shift)
179
179
  end
180
180
  end
181
181
  end
182
-
182
+
183
+ def query_expression_from_hash(hash)
184
+ return '' if hash.right_blank?
185
+ expression = []
186
+ hash.each do |key, value|
187
+ expression << "#{key}=#{escape(value)}"
188
+ end
189
+ expression.join(' AND ')
190
+ end
191
+
183
192
  # Retrieve a list of SDB domains from Amazon.
184
193
  #
185
194
  # Returns a hash:
@@ -245,6 +254,27 @@ module RightAws
245
254
  on_exception
246
255
  end
247
256
 
257
+ # Query Metadata for Domain
258
+ #
259
+ # Returns a hash on success or an exception on error.
260
+ #
261
+ # example:
262
+ # sdb = RightAWS:::SdbInterface.new
263
+ # sdb.domain_metadata('toys') # => {:attribute_values_size_bytes=>"2754",
264
+ # :item_count=>"25",
265
+ # :item_names_size_bytes=>"900",
266
+ # :timestamp=>"1291890409",
267
+ # :attribute_name_count=>"7",
268
+ # :box_usage=>"0.0000071759",
269
+ # :attribute_names_size_bytes=>"48",
270
+ # :attribute_value_count=>"154",
271
+ # :request_id=>"79bbfe8f-f0c9-59a2-0963-16d5fc6c3c52"}
272
+ # see http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/index.html?SDB_API_DomainMetadata.html
273
+ def domain_metadata(domain)
274
+ link = generate_request("DomainMetadata","DomainName"=>domain)
275
+ request_info(link,QSdbGenericParser.new)
276
+ end
277
+
248
278
  # Delete SDB domain at Amazon.
249
279
  #
250
280
  # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
@@ -315,6 +345,37 @@ module RightAws
315
345
  rescue Exception
316
346
  on_exception
317
347
  end
348
+
349
+ # Add/Replace attributes for multiple items at a time.
350
+ #
351
+ # Params:
352
+ # domain_name = DomainName
353
+ # items = {
354
+ # 'Item1' => {
355
+ # 'nameA' => [valueA1, valueA2,..., valueAN],
356
+ # ...
357
+ # 'nameB' => [valueB1, valueB2,..., valueBN]
358
+ # },
359
+ # 'Item2' => {
360
+ # 'nameC' => [valueC1, valueC2,..., valueCN],
361
+ # ...
362
+ # 'nameD' => [valueD1, valueD2,..., valueDN]
363
+ # }
364
+ # }
365
+ # replace = :replace | any other value to skip replacement
366
+ #
367
+ # Usage of batch_put_attributes is similar to put_attributes except that
368
+ # instead of supplying an item_name and a hash of attributes, you supply a
369
+ # hash of item names to attributes.
370
+ #
371
+ # See: http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/index.html?SDB_API_BatchPutAttributes.html
372
+ def batch_put_attributes(domain_name, items, replace = false)
373
+ params = { 'DomainName' => domain_name }.merge(pack_attributes(items, replace, true))
374
+ link = generate_request("BatchPutAttributes", params)
375
+ request_info( link, QSdbSimpleParser.new)
376
+ rescue Exception
377
+ on_exception
378
+ end
318
379
 
319
380
  # Retrieve SDB item's attribute(s).
320
381
  #
@@ -338,12 +399,21 @@ module RightAws
338
399
  # :box_usage => "0.0000093222",
339
400
  # :request_id => "81273d21-001-1111-b3f9-512d91d29ac8" }
340
401
  #
402
+ # # request all attributes using a consistent read
403
+ # # see: http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/index.html?ConsistencySummary.html
404
+ # sdb.get_attributes('family', 'toys', nil, true) # => { :attributes => {"cat" => ["clew", "Jons_socks", "mouse"] },
405
+ # "Silvia" => ["beetle", "rolling_pin", "kids"],
406
+ # "Jon" => ["vacuum_cleaner", "hammer", "spade"]},
407
+ # :box_usage => "0.0000093222",
408
+ # :request_id => "81273d21-000-1111-b3f9-512d91d29ac8" }
409
+ #
341
410
  # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_GetAttributes.html
342
411
  #
343
- def get_attributes(domain_name, item_name, attribute_name=nil)
344
- link = generate_request("GetAttributes", 'DomainName' => domain_name,
345
- 'ItemName' => item_name,
346
- 'AttributeName' => attribute_name )
412
+ def get_attributes(domain_name, item_name, attribute_name=nil, consistent_read=nil)
413
+ link = generate_request("GetAttributes", 'DomainName' => domain_name,
414
+ 'ItemName' => item_name,
415
+ 'AttributeName' => attribute_name,
416
+ 'ConsistentRead' => consistent_read )
347
417
  res = request_info(link, QSdbGetAttributesParser.new)
348
418
  res[:attributes].each_value do |values|
349
419
  values.collect! { |e| sdb_to_ruby(e) }
@@ -440,9 +510,152 @@ module RightAws
440
510
  on_exception
441
511
  end
442
512
 
513
+ # Perform a query and fetch specified attributes.
514
+ # If attributes are not specified then fetches the whole list of attributes.
515
+ #
516
+ #
517
+ # Returns a hash:
518
+ # { :box_usage => string,
519
+ # :request_id => string,
520
+ # :next_token => string,
521
+ # :items => [ { ItemName1 => { attribute1 => value1, ... attributeM => valueM } },
522
+ # { ItemName2 => {...}}, ... ]
523
+ #
524
+ # Example:
525
+ #
526
+ # sdb.query_with_attributes(domain, ['hobby', 'country'], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
527
+ # { :request_id => "06057228-70d0-4487-89fb-fd9c028580d3",
528
+ # :items =>
529
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
530
+ # { "hobby" => ["cooking", "flowers", "cats"],
531
+ # "country" => ["Russia"]}},
532
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
533
+ # { "hobby" => ["patchwork", "bundle jumping"],
534
+ # "country" => ["USA"]}}, ... ],
535
+ # :box_usage=>"0.0000504786"}
536
+ #
537
+ # sdb.query_with_attributes(domain, [], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
538
+ # { :request_id => "75bb19db-a529-4f69-b86f-5e3800f79a45",
539
+ # :items =>
540
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
541
+ # { "hobby" => ["cooking", "flowers", "cats"],
542
+ # "name" => ["Mary"],
543
+ # "country" => ["Russia"],
544
+ # "gender" => ["female"],
545
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
546
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
547
+ # { "hobby" => ["patchwork", "bundle jumping"],
548
+ # "name" => ["Mary"],
549
+ # "country" => ["USA"],
550
+ # "gender" => ["female"],
551
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ],
552
+ # :box_usage=>"0.0000506668"}
553
+ #
554
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_QueryWithAttributes.html
555
+ #
556
+ def query_with_attributes(domain_name, attributes=[], query_expression = nil, max_number_of_items = nil, next_token = nil)
557
+ attributes = Array(attributes)
558
+ query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
559
+ @last_query_expression = query_expression
560
+ #
561
+ request_params = { 'DomainName' => domain_name,
562
+ 'QueryExpression' => query_expression,
563
+ 'MaxNumberOfItems' => max_number_of_items,
564
+ 'NextToken' => next_token }
565
+ attributes.each_with_index do |attribute, idx|
566
+ request_params["AttributeName.#{idx+1}"] = attribute
567
+ end
568
+ link = generate_request("QueryWithAttributes", request_params)
569
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
570
+ # return result if no block given
571
+ return result unless block_given?
572
+ # loop if block if given
573
+ begin
574
+ # the block must return true if it wanna continue
575
+ break unless yield(result) && result[:next_token]
576
+ # make new request
577
+ request_params['NextToken'] = result[:next_token]
578
+ link = generate_request("QueryWithAttributes", request_params)
579
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
580
+ end while true
581
+ rescue Exception
582
+ on_exception
583
+ end
584
+
585
+ # Perform SQL-like select and fetch attributes.
586
+ # 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.
587
+ # (Use array to pass select_expression params to avoid manual escaping).
588
+ #
589
+ # sdb.select(["select * from my_domain where gender=?", 'female']) #=>
590
+ # {:request_id =>"8241b843-0fb9-4d66-9100-effae12249ec",
591
+ # :items =>
592
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
593
+ # {"hobby" => ["cooking", "flowers", "cats"],
594
+ # "name" => ["Mary"],
595
+ # "country" => ["Russia"],
596
+ # "gender" => ["female"],
597
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
598
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
599
+ # {"hobby" => ["patchwork", "bundle jumping"],
600
+ # "name" => ["Mary"],
601
+ # "country" => ["USA"],
602
+ # "gender" => ["female"],
603
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ]
604
+ # :box_usage =>"0.0000506197"}
605
+ #
606
+ # sdb.select('select country, name from my_domain') #=>
607
+ # {:request_id=>"b1600198-c317-413f-a8dc-4e7f864a940a",
608
+ # :items=>
609
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
610
+ # { "376d2e00-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Putin"], "country"=>["Russia"]} },
611
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} },
612
+ # { "372ebbd4-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Bush"], "country"=>["USA"]} },
613
+ # { "37a4e552-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Medvedev"], "country"=>["Russia"]} },
614
+ # { "38278dfe-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
615
+ # { "37df6c36-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} } ],
616
+ # :box_usage=>"0.0000777663"}
617
+ #
618
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_Select.html
619
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingSelect.html
620
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDBLimits.html
621
+ #
622
+ def select(select_expression, next_token = nil)
623
+ select_expression = query_expression_from_array(select_expression) if select_expression.is_a?(Array)
624
+ @last_query_expression = select_expression
625
+ #
626
+ request_params = { 'SelectExpression' => select_expression,
627
+ 'NextToken' => next_token }
628
+ link = generate_request("Select", request_params)
629
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
630
+ return result unless block_given?
631
+ # loop if block if given
632
+ begin
633
+ # the block must return true if it wanna continue
634
+ break unless yield(result) && result[:next_token]
635
+ # make new request
636
+ request_params['NextToken'] = result[:next_token]
637
+ link = generate_request("Select", request_params)
638
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
639
+ end while true
640
+ rescue Exception
641
+ on_exception
642
+ end
643
+
443
644
  #-----------------------------------------------------------------
444
645
  # PARSERS:
445
646
  #-----------------------------------------------------------------
647
+ class QSdbGenericParser < RightAWSParser #:nodoc:
648
+ def reset
649
+ @result = {}
650
+ end
651
+ def tagend(name)
652
+ case full_tag_name
653
+ when %r{/(DomainMetadataResult|ResponseMetadata)/}
654
+ @result[name.right_underscore.to_sym] = @text
655
+ end
656
+ end
657
+ end
658
+
446
659
  class QSdbListDomainParser < RightAWSParser #:nodoc:
447
660
  def reset
448
661
  @result = { :domains => [] }
@@ -498,6 +711,52 @@ module RightAws
498
711
  end
499
712
  end
500
713
 
714
+ class QSdbQueryWithAttributesParser < RightAWSParser #:nodoc:
715
+ def reset
716
+ @result = { :items => [] }
717
+ end
718
+ def tagend(name)
719
+ case name
720
+ when 'Name'
721
+ case @xmlpath
722
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item'
723
+ @item = @text
724
+ @result[:items] << { @item => {} }
725
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item/Attribute'
726
+ @attribute = @text
727
+ @result[:items].last[@item][@attribute] ||= []
728
+ end
729
+ when 'RequestId' then @result[:request_id] = @text
730
+ when 'BoxUsage' then @result[:box_usage] = @text
731
+ when 'NextToken' then @result[:next_token] = @text
732
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
733
+ end
734
+ end
735
+ end
736
+
737
+ class QSdbSelectParser < RightAWSParser #:nodoc:
738
+ def reset
739
+ @result = { :items => [] }
740
+ end
741
+ def tagend(name)
742
+ case name
743
+ when 'Name'
744
+ case @xmlpath
745
+ when 'SelectResponse/SelectResult/Item'
746
+ @item = @text
747
+ @result[:items] << { @item => {} }
748
+ when 'SelectResponse/SelectResult/Item/Attribute'
749
+ @attribute = @text
750
+ @result[:items].last[@item][@attribute] ||= []
751
+ end
752
+ when 'RequestId' then @result[:request_id] = @text
753
+ when 'BoxUsage' then @result[:box_usage] = @text
754
+ when 'NextToken' then @result[:next_token] = @text
755
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
756
+ end
757
+ end
758
+ end
759
+
501
760
  end
502
761
 
503
762
  end