revans_right_aws 2.0.1

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 (52) hide show
  1. data/.gemtest +0 -0
  2. data/History.txt +284 -0
  3. data/Manifest.txt +50 -0
  4. data/README.txt +167 -0
  5. data/Rakefile +110 -0
  6. data/lib/acf/right_acf_interface.rb +485 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  8. data/lib/acf/right_acf_streaming_interface.rb +236 -0
  9. data/lib/acw/right_acw_interface.rb +249 -0
  10. data/lib/as/right_as_interface.rb +699 -0
  11. data/lib/awsbase/benchmark_fix.rb +39 -0
  12. data/lib/awsbase/right_awsbase.rb +978 -0
  13. data/lib/awsbase/support.rb +115 -0
  14. data/lib/ec2/right_ec2.rb +395 -0
  15. data/lib/ec2/right_ec2_ebs.rb +452 -0
  16. data/lib/ec2/right_ec2_images.rb +373 -0
  17. data/lib/ec2/right_ec2_instances.rb +755 -0
  18. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  19. data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
  20. data/lib/ec2/right_ec2_security_groups.rb +277 -0
  21. data/lib/ec2/right_ec2_spot_instances.rb +399 -0
  22. data/lib/ec2/right_ec2_vpc.rb +571 -0
  23. data/lib/elb/right_elb_interface.rb +496 -0
  24. data/lib/rds/right_rds_interface.rb +998 -0
  25. data/lib/right_aws.rb +83 -0
  26. data/lib/s3/right_s3.rb +1126 -0
  27. data/lib/s3/right_s3_interface.rb +1199 -0
  28. data/lib/sdb/active_sdb.rb +1122 -0
  29. data/lib/sdb/right_sdb_interface.rb +721 -0
  30. data/lib/sqs/right_sqs.rb +388 -0
  31. data/lib/sqs/right_sqs_gen2.rb +343 -0
  32. data/lib/sqs/right_sqs_gen2_interface.rb +524 -0
  33. data/lib/sqs/right_sqs_interface.rb +594 -0
  34. data/test/acf/test_helper.rb +2 -0
  35. data/test/acf/test_right_acf.rb +138 -0
  36. data/test/ec2/test_helper.rb +2 -0
  37. data/test/ec2/test_right_ec2.rb +108 -0
  38. data/test/http_connection.rb +87 -0
  39. data/test/rds/test_helper.rb +2 -0
  40. data/test/rds/test_right_rds.rb +120 -0
  41. data/test/s3/test_helper.rb +2 -0
  42. data/test/s3/test_right_s3.rb +421 -0
  43. data/test/s3/test_right_s3_stubbed.rb +97 -0
  44. data/test/sdb/test_active_sdb.rb +357 -0
  45. data/test/sdb/test_helper.rb +3 -0
  46. data/test/sdb/test_right_sdb.rb +253 -0
  47. data/test/sqs/test_helper.rb +2 -0
  48. data/test/sqs/test_right_sqs.rb +291 -0
  49. data/test/sqs/test_right_sqs_gen2.rb +264 -0
  50. data/test/test_credentials.rb +37 -0
  51. data/test/ts_right_aws.rb +14 -0
  52. metadata +169 -0
@@ -0,0 +1,721 @@
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(items_or_attributes, replace = false, batch = false) #:nodoc:
93
+ if batch
94
+ index = 0
95
+ items_or_attributes.inject({}){|result, (item_name, attributes)|
96
+ item_prefix = "Item.#{index}."
97
+ result["#{item_prefix}ItemName"] = item_name.to_s
98
+ result.merge!(
99
+ pack_single_item_attributes(attributes, replace, item_prefix))
100
+ index += 1
101
+ result
102
+ }
103
+ else
104
+ pack_single_item_attributes(items_or_attributes, replace)
105
+ end
106
+ end
107
+
108
+ def pack_single_item_attributes(attributes, replace, prefix = "")
109
+ result = {}
110
+ if attributes
111
+ idx = 0
112
+ skip_values = attributes.is_a?(Array)
113
+ attributes.each do |attribute, values|
114
+ # set replacement attribute
115
+ result["#{prefix}Attribute.#{idx}.Replace"] = 'true' if replace
116
+ # pack Name/Value
117
+ unless values.nil?
118
+ # Array(values) does not work here:
119
+ # - Array('') => [] but we wanna get here ['']
120
+ [values].flatten.each do |value|
121
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
122
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
123
+ idx += 1
124
+ end
125
+ else
126
+ result["#{prefix}Attribute.#{idx}.Name"] = attribute
127
+ result["#{prefix}Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
128
+ idx += 1
129
+ end
130
+ end
131
+ end
132
+ result
133
+ end
134
+
135
+ # Use this helper to manually escape the fields in the query expressions.
136
+ # To escape the single quotes and backslashes and to wrap the string into the single quotes.
137
+ #
138
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API.html
139
+ #
140
+ def escape(value)
141
+ %Q{'#{value.to_s.gsub(/(['\\])/){ "\\#{$1}" }}'} if value
142
+ end
143
+
144
+ # Convert a Ruby language value to a SDB value by replacing Ruby nil with the user's chosen string representation of nil.
145
+ # Non-nil values are unaffected by this filter.
146
+ def ruby_to_sdb(value)
147
+ value.nil? ? @nil_rep : value
148
+ end
149
+
150
+ # Convert a SDB value to a Ruby language value by replacing the user's chosen string representation of nil with Ruby nil.
151
+ # Values are unaffected by this filter unless they match the nil representation exactly.
152
+ def sdb_to_ruby(value)
153
+ value.eql?(@nil_rep) ? nil : value
154
+ end
155
+
156
+ # 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.
157
+ # (This method affects on a passed response value)
158
+ def select_response_to_ruby(response) #:nodoc:
159
+ response[:items].each_with_index do |item, idx|
160
+ item.each do |key, attributes|
161
+ attributes.each do |name, values|
162
+ values.collect! { |value| sdb_to_ruby(value) }
163
+ end
164
+ end
165
+ end
166
+ response
167
+ end
168
+
169
+ # Create query expression from an array.
170
+ # (similar to ActiveRecord::Base#find using :conditions => ['query', param1, .., paramN])
171
+ #
172
+ def query_expression_from_array(params) #:nodoc:
173
+ return '' if params.blank?
174
+ query = params.shift.to_s
175
+ query.gsub(/(\\)?(\?)/) do
176
+ if $1 # if escaped '\?' is found - replace it by '?' without backslash
177
+ "?"
178
+ else # well, if no backslash precedes '?' then replace it by next param from the list
179
+ escape(params.shift)
180
+ end
181
+ end
182
+ end
183
+
184
+ def query_expression_from_hash(hash)
185
+ return '' if hash.blank?
186
+ expression = []
187
+ hash.each do |key, value|
188
+ expression << "#{key}=#{escape(value)}"
189
+ end
190
+ expression.join(' AND ')
191
+ end
192
+
193
+ # Retrieve a list of SDB domains from Amazon.
194
+ #
195
+ # Returns a hash:
196
+ # { :domains => [domain1, ..., domainN],
197
+ # :next_token => string || nil,
198
+ # :box_usage => string,
199
+ # :request_id => string }
200
+ #
201
+ # Example:
202
+ #
203
+ # sdb = RightAws::SdbInterface.new
204
+ # sdb.list_domains #=> { :box_usage => "0.0000071759",
205
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982",
206
+ # :domains => ["toys", "dolls"]}
207
+ #
208
+ # 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,
209
+ # list_domains will end.
210
+ #
211
+ # sdb.list_domains(10) do |result| # list by 10 domains per iteration
212
+ # puts result.inspect
213
+ # true
214
+ # end
215
+ #
216
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_ListDomains.html
217
+ #
218
+ def list_domains(max_number_of_domains = nil, next_token = nil )
219
+ request_params = { 'MaxNumberOfDomains' => max_number_of_domains,
220
+ 'NextToken' => next_token }
221
+ link = generate_request("ListDomains", request_params)
222
+ result = request_info(link, QSdbListDomainParser.new)
223
+ # return result if no block given
224
+ return result unless block_given?
225
+ # loop if block if given
226
+ begin
227
+ # the block must return true if it wanna continue
228
+ break unless yield(result) && result[:next_token]
229
+ # make new request
230
+ request_params['NextToken'] = result[:next_token]
231
+ link = generate_request("ListDomains", request_params)
232
+ result = request_info(link, QSdbListDomainParser.new)
233
+ end while true
234
+ rescue Exception
235
+ on_exception
236
+ end
237
+
238
+ # Create new SDB domain at Amazon.
239
+ #
240
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
241
+ # (Amazon raises no errors if the domain already exists).
242
+ #
243
+ # Example:
244
+ #
245
+ # sdb = RightAws::SdbInterface.new
246
+ # sdb.create_domain('toys') # => { :box_usage => "0.0000071759",
247
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982" }
248
+ #
249
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_CreateDomain.html
250
+ def create_domain(domain_name)
251
+ link = generate_request("CreateDomain",
252
+ 'DomainName' => domain_name)
253
+ request_info(link, QSdbSimpleParser.new)
254
+ rescue Exception
255
+ on_exception
256
+ end
257
+
258
+ # Delete SDB domain at Amazon.
259
+ #
260
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
261
+ # (Amazon raises no errors if the domain does not exist).
262
+ #
263
+ # Example:
264
+ #
265
+ # sdb = RightAws::SdbInterface.new
266
+ # sdb.delete_domain('toys') # => { :box_usage => "0.0000071759",
267
+ # :request_id => "976709f9-0111-2345-92cb-9ce90acd0982" }
268
+ #
269
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_DeleteDomain.html
270
+ #
271
+ def delete_domain(domain_name)
272
+ link = generate_request("DeleteDomain",
273
+ 'DomainName' => domain_name)
274
+ request_info(link, QSdbSimpleParser.new)
275
+ rescue Exception
276
+ on_exception
277
+ end
278
+
279
+ # Add/Replace item attributes.
280
+ #
281
+ # Params:
282
+ # domain_name = DomainName
283
+ # item_name = ItemName
284
+ # attributes = {
285
+ # 'nameA' => [valueA1,..., valueAN],
286
+ # ...
287
+ # 'nameZ' => [valueZ1,..., valueZN]
288
+ # }
289
+ # replace = :replace | any other value to skip replacement
290
+ #
291
+ # Returns a hash: { :box_usage, :request_id } on success or an exception on error.
292
+ # (Amazon raises no errors if the attribute was not overridden, as when the :replace param is unset).
293
+ #
294
+ # Example:
295
+ #
296
+ # sdb = RightAws::SdbInterface.new
297
+ # sdb.create_domain 'family'
298
+ #
299
+ # attributes = {}
300
+ # # create attributes for Jon and Silvia
301
+ # attributes['Jon'] = %w{ car beer }
302
+ # attributes['Silvia'] = %w{ beetle rolling_pin kids }
303
+ # sdb.put_attributes 'family', 'toys', attributes #=> ok
304
+ # # now: Jon=>[car, beer], Silvia=>[beetle, rolling_pin, kids]
305
+ #
306
+ # # add attributes to Jon
307
+ # attributes.delete('Silvia')
308
+ # attributes['Jon'] = %w{ girls pub }
309
+ # sdb.put_attributes 'family', 'toys', attributes #=> ok
310
+ # # now: Jon=>[car, beer, girls, pub], Silvia=>[beetle, rolling_pin, kids]
311
+ #
312
+ # # replace attributes for Jon and add to a cat (the cat had no attributes before)
313
+ # attributes['Jon'] = %w{ vacuum_cleaner hammer spade }
314
+ # attributes['cat'] = %w{ mouse clew Jons_socks }
315
+ # sdb.put_attributes 'family', 'toys', attributes, :replace #=> ok
316
+ # # now: Jon=>[vacuum_cleaner, hammer, spade], Silvia=>[beetle, rolling_pin, kids], cat=>[mouse, clew, Jons_socks]
317
+ #
318
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_PutAttributes.html
319
+ #
320
+ def put_attributes(domain_name, item_name, attributes, replace = false)
321
+ params = { 'DomainName' => domain_name,
322
+ 'ItemName' => item_name }.merge(pack_attributes(attributes, replace))
323
+ link = generate_request("PutAttributes", params)
324
+ request_info( link, QSdbSimpleParser.new )
325
+ rescue Exception
326
+ on_exception
327
+ end
328
+
329
+ # Add/Replace attributes for multiple items at a time.
330
+ #
331
+ # Params:
332
+ # domain_name = DomainName
333
+ # items = {
334
+ # 'Item1' => {
335
+ # 'nameA' => [valueA1, valueA2,..., valueAN],
336
+ # ...
337
+ # 'nameB' => [valueB1, valueB2,..., valueBN]
338
+ # },
339
+ # 'Item2' => {
340
+ # 'nameC' => [valueC1, valueC2,..., valueCN],
341
+ # ...
342
+ # 'nameD' => [valueD1, valueD2,..., valueDN]
343
+ # }
344
+ # }
345
+ # replace = :replace | any other value to skip replacement
346
+ #
347
+ # Usage of batch_put_attributes is similar to put_attributes except that
348
+ # instead of supplying an item_name and a hash of attributes, you supply a
349
+ # hash of item names to attributes.
350
+ #
351
+ # See: http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/index.html?SDB_API_BatchPutAttributes.html
352
+ def batch_put_attributes(domain_name, items, replace = false)
353
+ params = { 'DomainName' => domain_name }.merge(pack_attributes(items, replace, true))
354
+ link = generate_request("BatchPutAttributes", params)
355
+ request_info( link, QSdbSimpleParser.new)
356
+ rescue Exception
357
+ on_exception
358
+ end
359
+
360
+ # Retrieve SDB item's attribute(s).
361
+ #
362
+ # Returns a hash:
363
+ # { :box_usage => string,
364
+ # :request_id => string,
365
+ # :attributes => { 'nameA' => [valueA1,..., valueAN],
366
+ # ... ,
367
+ # 'nameZ' => [valueZ1,..., valueZN] } }
368
+ #
369
+ # Example:
370
+ # # request all attributes
371
+ # sdb.get_attributes('family', 'toys') # => { :attributes => {"cat" => ["clew", "Jons_socks", "mouse"] },
372
+ # "Silvia" => ["beetle", "rolling_pin", "kids"],
373
+ # "Jon" => ["vacuum_cleaner", "hammer", "spade"]},
374
+ # :box_usage => "0.0000093222",
375
+ # :request_id => "81273d21-000-1111-b3f9-512d91d29ac8" }
376
+ #
377
+ # # request cat's attributes only
378
+ # sdb.get_attributes('family', 'toys', 'cat') # => { :attributes => {"cat" => ["clew", "Jons_socks", "mouse"] },
379
+ # :box_usage => "0.0000093222",
380
+ # :request_id => "81273d21-001-1111-b3f9-512d91d29ac8" }
381
+ #
382
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_GetAttributes.html
383
+ #
384
+ def get_attributes(domain_name, item_name, attribute_name=nil)
385
+ link = generate_request("GetAttributes", 'DomainName' => domain_name,
386
+ 'ItemName' => item_name,
387
+ 'AttributeName' => attribute_name )
388
+ res = request_info(link, QSdbGetAttributesParser.new)
389
+ res[:attributes].each_value do |values|
390
+ values.collect! { |e| sdb_to_ruby(e) }
391
+ end
392
+ res
393
+ rescue Exception
394
+ on_exception
395
+ end
396
+
397
+ # Delete value, attribute or item.
398
+ #
399
+ # Example:
400
+ # # delete 'vodka' and 'girls' from 'Jon' and 'mice' from 'cat'.
401
+ # sdb.delete_attributes 'family', 'toys', { 'Jon' => ['vodka', 'girls'], 'cat' => ['mice'] }
402
+ #
403
+ # # delete the all the values from attributes (i.e. delete the attributes)
404
+ # sdb.delete_attributes 'family', 'toys', { 'Jon' => [], 'cat' => [] }
405
+ # # or
406
+ # sdb.delete_attributes 'family', 'toys', [ 'Jon', 'cat' ]
407
+ #
408
+ # # delete all the attributes from item 'toys' (i.e. delete the item)
409
+ # sdb.delete_attributes 'family', 'toys'
410
+ #
411
+ # see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_DeleteAttributes.html
412
+ #
413
+ def delete_attributes(domain_name, item_name, attributes = nil)
414
+ params = { 'DomainName' => domain_name,
415
+ 'ItemName' => item_name }.merge(pack_attributes(attributes))
416
+ link = generate_request("DeleteAttributes", params)
417
+ request_info( link, QSdbSimpleParser.new )
418
+ rescue Exception
419
+ on_exception
420
+ end
421
+
422
+
423
+ # QUERY:
424
+
425
+ # Perform a query on SDB.
426
+ #
427
+ # Returns a hash:
428
+ # { :box_usage => string,
429
+ # :request_id => string,
430
+ # :next_token => string,
431
+ # :items => [ItemName1,..., ItemNameN] }
432
+ #
433
+ # Example:
434
+ #
435
+ # query = "['cat' = 'clew']"
436
+ # sdb.query('family', query) #=> hash of data
437
+ # sdb.query('family', query, 10) #=> hash of data with max of 10 items
438
+ #
439
+ # If a block is given, query will iteratively yield results to it as long as the block continues to return true.
440
+ #
441
+ # # List 10 items per iteration. Don't
442
+ # # forget to escape single quotes and backslashes and wrap all the items in single quotes.
443
+ # query = "['cat'='clew'] union ['dog'='Jon\\'s boot']"
444
+ # sdb.query('family', query, 10) do |result|
445
+ # puts result.inspect
446
+ # true
447
+ # end
448
+ #
449
+ # # Same query using automatic escaping...to use the auto escape, pass the query and its params as an array:
450
+ # query = [ "['cat'=?] union ['dog'=?]", "clew", "Jon's boot" ]
451
+ # sdb.query('family', query)
452
+ #
453
+ # query = [ "['cat'=?] union ['dog'=?] sort 'cat' desc", "clew", "Jon's boot" ]
454
+ # sdb.query('family', query)
455
+ #
456
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_Query.html
457
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SortingData.html
458
+ #
459
+ def query(domain_name, query_expression = nil, max_number_of_items = nil, next_token = nil)
460
+ query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
461
+ @last_query_expression = query_expression
462
+ #
463
+ request_params = { 'DomainName' => domain_name,
464
+ 'QueryExpression' => query_expression,
465
+ 'MaxNumberOfItems' => max_number_of_items,
466
+ 'NextToken' => next_token }
467
+ link = generate_request("Query", request_params)
468
+ result = request_info( link, QSdbQueryParser.new )
469
+ # return result if no block given
470
+ return result unless block_given?
471
+ # loop if block if given
472
+ begin
473
+ # the block must return true if it wanna continue
474
+ break unless yield(result) && result[:next_token]
475
+ # make new request
476
+ request_params['NextToken'] = result[:next_token]
477
+ link = generate_request("Query", request_params)
478
+ result = request_info( link, QSdbQueryParser.new )
479
+ end while true
480
+ rescue Exception
481
+ on_exception
482
+ end
483
+
484
+ # Perform a query and fetch specified attributes.
485
+ # If attributes are not specified then fetches the whole list of attributes.
486
+ #
487
+ #
488
+ # Returns a hash:
489
+ # { :box_usage => string,
490
+ # :request_id => string,
491
+ # :next_token => string,
492
+ # :items => [ { ItemName1 => { attribute1 => value1, ... attributeM => valueM } },
493
+ # { ItemName2 => {...}}, ... ]
494
+ #
495
+ # Example:
496
+ #
497
+ # sdb.query_with_attributes(domain, ['hobby', 'country'], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
498
+ # { :request_id => "06057228-70d0-4487-89fb-fd9c028580d3",
499
+ # :items =>
500
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
501
+ # { "hobby" => ["cooking", "flowers", "cats"],
502
+ # "country" => ["Russia"]}},
503
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
504
+ # { "hobby" => ["patchwork", "bundle jumping"],
505
+ # "country" => ["USA"]}}, ... ],
506
+ # :box_usage=>"0.0000504786"}
507
+ #
508
+ # sdb.query_with_attributes(domain, [], "['gender'='female'] intersection ['name' starts-with ''] sort 'name'") #=>
509
+ # { :request_id => "75bb19db-a529-4f69-b86f-5e3800f79a45",
510
+ # :items =>
511
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
512
+ # { "hobby" => ["cooking", "flowers", "cats"],
513
+ # "name" => ["Mary"],
514
+ # "country" => ["Russia"],
515
+ # "gender" => ["female"],
516
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
517
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
518
+ # { "hobby" => ["patchwork", "bundle jumping"],
519
+ # "name" => ["Mary"],
520
+ # "country" => ["USA"],
521
+ # "gender" => ["female"],
522
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ],
523
+ # :box_usage=>"0.0000506668"}
524
+ #
525
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_QueryWithAttributes.html
526
+ #
527
+ def query_with_attributes(domain_name, attributes=[], query_expression = nil, max_number_of_items = nil, next_token = nil)
528
+ attributes = Array(attributes)
529
+ query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
530
+ @last_query_expression = query_expression
531
+ #
532
+ request_params = { 'DomainName' => domain_name,
533
+ 'QueryExpression' => query_expression,
534
+ 'MaxNumberOfItems' => max_number_of_items,
535
+ 'NextToken' => next_token }
536
+ attributes.each_with_index do |attribute, idx|
537
+ request_params["AttributeName.#{idx+1}"] = attribute
538
+ end
539
+ link = generate_request("QueryWithAttributes", request_params)
540
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
541
+ # return result if no block given
542
+ return result unless block_given?
543
+ # loop if block if given
544
+ begin
545
+ # the block must return true if it wanna continue
546
+ break unless yield(result) && result[:next_token]
547
+ # make new request
548
+ request_params['NextToken'] = result[:next_token]
549
+ link = generate_request("QueryWithAttributes", request_params)
550
+ result = select_response_to_ruby(request_info( link, QSdbQueryWithAttributesParser.new ))
551
+ end while true
552
+ rescue Exception
553
+ on_exception
554
+ end
555
+
556
+ # Perform SQL-like select and fetch attributes.
557
+ # 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.
558
+ # (Use array to pass select_expression params to avoid manual escaping).
559
+ #
560
+ # sdb.select(["select * from my_domain where gender=?", 'female']) #=>
561
+ # {:request_id =>"8241b843-0fb9-4d66-9100-effae12249ec",
562
+ # :items =>
563
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=>
564
+ # {"hobby" => ["cooking", "flowers", "cats"],
565
+ # "name" => ["Mary"],
566
+ # "country" => ["Russia"],
567
+ # "gender" => ["female"],
568
+ # "id" => ["035f1ba8-dbd8-11dd-80bd-001bfc466dd7"]}},
569
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=>
570
+ # {"hobby" => ["patchwork", "bundle jumping"],
571
+ # "name" => ["Mary"],
572
+ # "country" => ["USA"],
573
+ # "gender" => ["female"],
574
+ # "id" => ["0327614a-dbd8-11dd-80bd-001bfc466dd7"]}}, ... ]
575
+ # :box_usage =>"0.0000506197"}
576
+ #
577
+ # sdb.select('select country, name from my_domain') #=>
578
+ # {:request_id=>"b1600198-c317-413f-a8dc-4e7f864a940a",
579
+ # :items=>
580
+ # [ { "035f1ba8-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
581
+ # { "376d2e00-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Putin"], "country"=>["Russia"]} },
582
+ # { "0327614a-dbd8-11dd-80bd-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} },
583
+ # { "372ebbd4-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Bush"], "country"=>["USA"]} },
584
+ # { "37a4e552-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Medvedev"], "country"=>["Russia"]} },
585
+ # { "38278dfe-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["Russia"]} },
586
+ # { "37df6c36-75b0-11dd-9557-001bfc466dd7"=> {"name"=>["Mary"], "country"=>["USA"]} } ],
587
+ # :box_usage=>"0.0000777663"}
588
+ #
589
+ # see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDB_API_Select.html
590
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingSelect.html
591
+ # http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SDBLimits.html
592
+ #
593
+ def select(select_expression, next_token = nil)
594
+ select_expression = query_expression_from_array(select_expression) if select_expression.is_a?(Array)
595
+ @last_query_expression = select_expression
596
+ #
597
+ request_params = { 'SelectExpression' => select_expression,
598
+ 'NextToken' => next_token }
599
+ link = generate_request("Select", request_params)
600
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
601
+ return result unless block_given?
602
+ # loop if block if given
603
+ begin
604
+ # the block must return true if it wanna continue
605
+ break unless yield(result) && result[:next_token]
606
+ # make new request
607
+ request_params['NextToken'] = result[:next_token]
608
+ link = generate_request("Select", request_params)
609
+ result = select_response_to_ruby(request_info( link, QSdbSelectParser.new ))
610
+ end while true
611
+ rescue Exception
612
+ on_exception
613
+ end
614
+
615
+ #-----------------------------------------------------------------
616
+ # PARSERS:
617
+ #-----------------------------------------------------------------
618
+ class QSdbListDomainParser < RightAWSParser #:nodoc:
619
+ def reset
620
+ @result = { :domains => [] }
621
+ end
622
+ def tagend(name)
623
+ case name
624
+ when 'NextToken' then @result[:next_token] = @text
625
+ when 'DomainName' then @result[:domains] << @text
626
+ when 'BoxUsage' then @result[:box_usage] = @text
627
+ when 'RequestId' then @result[:request_id] = @text
628
+ end
629
+ end
630
+ end
631
+
632
+ class QSdbSimpleParser < RightAWSParser #:nodoc:
633
+ def reset
634
+ @result = {}
635
+ end
636
+ def tagend(name)
637
+ case name
638
+ when 'BoxUsage' then @result[:box_usage] = @text
639
+ when 'RequestId' then @result[:request_id] = @text
640
+ end
641
+ end
642
+ end
643
+
644
+ class QSdbGetAttributesParser < RightAWSParser #:nodoc:
645
+ def reset
646
+ @last_attribute_name = nil
647
+ @result = { :attributes => {} }
648
+ end
649
+ def tagend(name)
650
+ case name
651
+ when 'Name' then @last_attribute_name = @text
652
+ when 'Value' then (@result[:attributes][@last_attribute_name] ||= []) << @text
653
+ when 'BoxUsage' then @result[:box_usage] = @text
654
+ when 'RequestId' then @result[:request_id] = @text
655
+ end
656
+ end
657
+ end
658
+
659
+ class QSdbQueryParser < RightAWSParser #:nodoc:
660
+ def reset
661
+ @result = { :items => [] }
662
+ end
663
+ def tagend(name)
664
+ case name
665
+ when 'ItemName' then @result[:items] << @text
666
+ when 'BoxUsage' then @result[:box_usage] = @text
667
+ when 'RequestId' then @result[:request_id] = @text
668
+ when 'NextToken' then @result[:next_token] = @text
669
+ end
670
+ end
671
+ end
672
+
673
+ class QSdbQueryWithAttributesParser < RightAWSParser #:nodoc:
674
+ def reset
675
+ @result = { :items => [] }
676
+ end
677
+ def tagend(name)
678
+ case name
679
+ when 'Name'
680
+ case @xmlpath
681
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item'
682
+ @item = @text
683
+ @result[:items] << { @item => {} }
684
+ when 'QueryWithAttributesResponse/QueryWithAttributesResult/Item/Attribute'
685
+ @attribute = @text
686
+ @result[:items].last[@item][@attribute] ||= []
687
+ end
688
+ when 'RequestId' then @result[:request_id] = @text
689
+ when 'BoxUsage' then @result[:box_usage] = @text
690
+ when 'NextToken' then @result[:next_token] = @text
691
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
692
+ end
693
+ end
694
+ end
695
+
696
+ class QSdbSelectParser < RightAWSParser #:nodoc:
697
+ def reset
698
+ @result = { :items => [] }
699
+ end
700
+ def tagend(name)
701
+ case name
702
+ when 'Name'
703
+ case @xmlpath
704
+ when 'SelectResponse/SelectResult/Item'
705
+ @item = @text
706
+ @result[:items] << { @item => {} }
707
+ when 'SelectResponse/SelectResult/Item/Attribute'
708
+ @attribute = @text
709
+ @result[:items].last[@item][@attribute] ||= []
710
+ end
711
+ when 'RequestId' then @result[:request_id] = @text
712
+ when 'BoxUsage' then @result[:box_usage] = @text
713
+ when 'NextToken' then @result[:next_token] = @text
714
+ when 'Value' then @result[:items].last[@item][@attribute] << @text
715
+ end
716
+ end
717
+ end
718
+
719
+ end
720
+
721
+ end