kerryb-right_aws 1.7.6 → 1.10.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.
- data/History.txt +78 -1
- data/Manifest.txt +3 -1
- data/README.txt +28 -8
- data/Rakefile +23 -7
- data/lib/acf/right_acf_interface.rb +379 -0
- data/lib/awsbase/right_awsbase.rb +150 -12
- data/lib/ec2/right_ec2.rb +595 -77
- data/lib/right_aws.rb +3 -3
- data/lib/s3/right_s3_interface.rb +3 -3
- data/lib/sdb/active_sdb.rb +267 -32
- data/lib/sdb/right_sdb_interface.rb +272 -48
- data/lib/sqs/right_sqs.rb +8 -0
- data/lib/sqs/right_sqs_gen2.rb +8 -0
- data/lib/sqs/right_sqs_gen2_interface.rb +17 -22
- data/lib/sqs/right_sqs_interface.rb +7 -13
- data/test/acf/test_helper.rb +2 -0
- data/test/acf/test_right_acf.rb +146 -0
- data/test/ec2/test_right_ec2.rb +32 -0
- data/test/s3/test_right_s3.rb +41 -10
- data/test/sdb/test_active_sdb.rb +59 -9
- data/test/sdb/test_helper.rb +1 -0
- data/test/sdb/test_right_sdb.rb +106 -6
- data/test/ts_right_aws.rb +1 -0
- metadata +30 -21
- data/lib/awsbase/file_fix.rb +0 -33
data/lib/right_aws.rb
CHANGED
@@ -36,7 +36,6 @@ require 'right_http_connection'
|
|
36
36
|
|
37
37
|
$:.unshift(File.dirname(__FILE__))
|
38
38
|
require 'awsbase/benchmark_fix'
|
39
|
-
require 'awsbase/file_fix'
|
40
39
|
require 'awsbase/support'
|
41
40
|
require 'awsbase/right_awsbase'
|
42
41
|
require 'ec2/right_ec2'
|
@@ -47,13 +46,14 @@ require 'sqs/right_sqs'
|
|
47
46
|
require 'sqs/right_sqs_gen2_interface'
|
48
47
|
require 'sqs/right_sqs_gen2'
|
49
48
|
require 'sdb/right_sdb_interface'
|
49
|
+
require 'acf/right_acf_interface'
|
50
50
|
|
51
51
|
|
52
52
|
module RightAws #:nodoc:
|
53
53
|
module VERSION #:nodoc:
|
54
54
|
MAJOR = 1
|
55
|
-
MINOR =
|
56
|
-
TINY =
|
55
|
+
MINOR = 10
|
56
|
+
TINY = 1
|
57
57
|
|
58
58
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
59
59
|
end
|
@@ -120,7 +120,8 @@ module RightAws
|
|
120
120
|
headers[:url].to_s[%r{^([a-z0-9._-]*)(/[^?]*)?(\?.+)?}i]
|
121
121
|
bucket_name, key_path, params_list = $1, $2, $3
|
122
122
|
# select request model
|
123
|
-
|
123
|
+
# No DNS
|
124
|
+
if is_dns_bucket?(bucket_name) and false
|
124
125
|
# fix a path
|
125
126
|
server = "#{bucket_name}.#{server}"
|
126
127
|
key_path ||= '/'
|
@@ -155,12 +156,11 @@ module RightAws
|
|
155
156
|
# set other headers
|
156
157
|
request['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
|
157
158
|
# prepare output hash
|
158
|
-
|
159
159
|
{ :request => request,
|
160
160
|
:server => server,
|
161
161
|
:port => @params[:port],
|
162
162
|
:protocol => @params[:protocol],
|
163
|
-
:proxy
|
163
|
+
:proxy => @params[:proxy] }
|
164
164
|
end
|
165
165
|
|
166
166
|
# Sends request to Amazon and parses the response.
|
data/lib/sdb/active_sdb.rb
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
begin
|
25
25
|
require 'uuidtools'
|
26
26
|
rescue LoadError => e
|
27
|
-
STDERR.puts("RightSDB
|
27
|
+
STDERR.puts("RightSDB requires the uuidtools gem. Run \'gem install uuidtools\' and try again.")
|
28
28
|
exit
|
29
29
|
end
|
30
30
|
|
@@ -101,6 +101,15 @@ module RightAws
|
|
101
101
|
# Create a new handle to an Sdb account. All handles share the same per process or per thread
|
102
102
|
# HTTP connection to Amazon Sdb. Each handle is for a specific account.
|
103
103
|
# The +params+ are passed through as-is to RightAws::SdbInterface.new
|
104
|
+
# Params:
|
105
|
+
# { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
|
106
|
+
# :port => 443 # Amazon service port: 80 or 443(default)
|
107
|
+
# :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
|
108
|
+
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
109
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
|
110
|
+
# :logger => Logger Object # Logger instance: logs to STDOUT if omitted
|
111
|
+
# :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')
|
112
|
+
|
104
113
|
def establish_connection(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
105
114
|
@connection = RightAws::SdbInterface.new(aws_access_key_id, aws_secret_access_key, params)
|
106
115
|
end
|
@@ -259,9 +268,10 @@ module RightAws
|
|
259
268
|
# Client.find_by_name('Matias Rust')
|
260
269
|
# Client.find_by_name_and_city('Putin','Moscow')
|
261
270
|
# Client.find_by_name_and_city_and_post('Medvedev','Moscow','president')
|
262
|
-
#
|
271
|
+
#
|
263
272
|
# Client.find_all_by_author('G.Bush jr')
|
264
273
|
# Client.find_all_by_age_and_gender_and_ethnicity('34','male','russian')
|
274
|
+
# Client.find_all_by_gender_and_country('male', 'Russia', :auto_load => true, :order => 'name desc')
|
265
275
|
#
|
266
276
|
# Returned records have to be +reloaded+ to access their attributes.
|
267
277
|
#
|
@@ -276,37 +286,231 @@ module RightAws
|
|
276
286
|
# Client.find(:all, :limit => 10, :next_token => Client.next_token)
|
277
287
|
# end while Client.next_token
|
278
288
|
#
|
289
|
+
# Sort oder:
|
290
|
+
# Client.find(:all, :order => 'gender')
|
291
|
+
# Client.find(:all, :order => 'name desc')
|
292
|
+
#
|
293
|
+
# Attributes auto load (be carefull - this may take lot of time for a huge bunch of records):
|
294
|
+
# Client.find(:first) #=> #<Client:0xb77d0d40 @attributes={"id"=>"2937601a-e45d-11dc-a75f-001bfc466dd7"}, @new_record=false>
|
295
|
+
# Client.find(:first, :auto_load => true) #=> #<Client:0xb77d0d40 @attributes={"id"=>"2937601a-e45d-11dc-a75f-001bfc466dd7", "name"=>["Cat"], "toys"=>["Jons socks", "clew", "mice"]}, @new_record=false>
|
296
|
+
#
|
297
|
+
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingQuery.html
|
298
|
+
#
|
279
299
|
def find(*args)
|
280
300
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
281
301
|
case args.first
|
282
|
-
when :all
|
283
|
-
when :first
|
284
|
-
else
|
302
|
+
when :all then find_every options
|
303
|
+
when :first then find_initial options
|
304
|
+
else find_from_ids args, options
|
285
305
|
end
|
286
306
|
end
|
287
307
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
308
|
+
# Perform a SQL-like select request.
|
309
|
+
#
|
310
|
+
# Single record:
|
311
|
+
#
|
312
|
+
# Client.select(:first)
|
313
|
+
# Client.select(:first, :conditions=> [ "name=? AND wife=?", "Jon", "Sandy"])
|
314
|
+
# Client.select(:first, :conditions=> { :name=>"Jon", :wife=>"Sandy" }, :select => :girfriends)
|
315
|
+
#
|
316
|
+
# Bunch of records:
|
317
|
+
#
|
318
|
+
# Client.select(:all)
|
319
|
+
# Client.select(:all, :limit => 10)
|
320
|
+
# Client.select(:all, :conditions=> [ "name=? AND 'girlfriend'=?", "Jon", "Judy"])
|
321
|
+
# Client.select(:all, :conditions=> { :name=>"Sandy" }, :limit => 3)
|
322
|
+
#
|
323
|
+
# Records by ids:
|
324
|
+
#
|
325
|
+
# Client.select('1')
|
326
|
+
# Client.select('1234987b4583475347523948')
|
327
|
+
# Client.select('1','2','3','4', :conditions=> ["toys=?", "beer"])
|
328
|
+
#
|
329
|
+
# Find helpers: RightAws::ActiveSdb::Base.select_by_... and RightAws::ActiveSdb::Base.select_all_by_...
|
330
|
+
#
|
331
|
+
# Client.select_by_name('Matias Rust')
|
332
|
+
# Client.select_by_name_and_city('Putin','Moscow')
|
333
|
+
# Client.select_by_name_and_city_and_post('Medvedev','Moscow','president')
|
334
|
+
#
|
335
|
+
# Client.select_all_by_author('G.Bush jr')
|
336
|
+
# Client.select_all_by_age_and_gender_and_ethnicity('34','male','russian')
|
337
|
+
# Client.select_all_by_gender_and_country('male', 'Russia', :order => 'name')
|
338
|
+
#
|
339
|
+
# Continue listing:
|
340
|
+
#
|
341
|
+
# # initial listing
|
342
|
+
# Client.select(:all, :limit => 10)
|
343
|
+
# # continue listing
|
344
|
+
# begin
|
345
|
+
# Client.select(:all, :limit => 10, :next_token => Client.next_token)
|
346
|
+
# end while Client.next_token
|
347
|
+
#
|
348
|
+
# Sort oder:
|
349
|
+
# If :order=>'attribute' option is specified then result response (ordered by 'attribute') will contain only items where attribute is defined (is not null).
|
350
|
+
#
|
351
|
+
# Client.select(:all) # returns all records
|
352
|
+
# Client.select(:all, :order => 'gender') # returns all records ordered by gender where gender attribute exists
|
353
|
+
# Client.select(:all, :order => 'name desc') # returns all records ordered by name in desc order where name attribute exists
|
354
|
+
#
|
355
|
+
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingSelect.html
|
356
|
+
#
|
357
|
+
def select(*args)
|
358
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
359
|
+
case args.first
|
360
|
+
when :all then sql_select(options)
|
361
|
+
when :first then sql_select(options.merge(:limit => 1)).first
|
362
|
+
else select_from_ids args, options
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def generate_id # :nodoc:
|
367
|
+
UUID.timestamp_create().to_s
|
368
|
+
end
|
369
|
+
|
370
|
+
protected
|
371
|
+
|
372
|
+
# Select
|
373
|
+
|
374
|
+
def select_from_ids(args, options) # :nodoc:
|
375
|
+
cond = []
|
376
|
+
# detect amount of records requested
|
377
|
+
bunch_of_records_requested = args.size > 1 || args.first.is_a?(Array)
|
378
|
+
# flatten ids
|
379
|
+
args = args.to_a.flatten
|
380
|
+
args.each { |id| cond << "id=#{self.connection.escape(id)}" }
|
381
|
+
ids_cond = "(#{cond.join(' OR ')})"
|
382
|
+
# user defined :conditions to string (if it was defined)
|
383
|
+
options[:conditions] = build_conditions(options[:conditions])
|
384
|
+
# join ids condition and user defined conditions
|
385
|
+
options[:conditions] = options[:conditions].blank? ? ids_cond : "(#{options[:conditions]}) AND #{ids_cond}"
|
386
|
+
result = sql_select(options)
|
387
|
+
# if one record was requested then return it
|
388
|
+
unless bunch_of_records_requested
|
389
|
+
record = result.first
|
390
|
+
# railse if nothing was found
|
391
|
+
raise ActiveSdbError.new("Couldn't find #{name} with ID #{args}") unless record
|
392
|
+
record
|
393
|
+
else
|
394
|
+
# if a bunch of records was requested then return check that we found all of them
|
395
|
+
# and return as an array
|
396
|
+
unless args.size == result.size
|
397
|
+
id_list = args.map{|i| "'#{i}'"}.join(',')
|
398
|
+
raise ActiveSdbError.new("Couldn't find all #{name} with IDs (#{id_list}) (found #{result.size} results, but was looking for #{args.size})")
|
399
|
+
else
|
400
|
+
result
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def sql_select(options) # :nodoc:
|
406
|
+
@next_token = options[:next_token]
|
407
|
+
select_expression = build_select(options)
|
292
408
|
# request items
|
293
|
-
query_result = self.connection.
|
409
|
+
query_result = self.connection.select(select_expression, @next_token)
|
410
|
+
@next_token = query_result[:next_token]
|
411
|
+
items = query_result[:items].map do |hash|
|
412
|
+
id, attributes = hash.shift
|
413
|
+
new_item = self.new( attributes.merge({ 'id' => id }))
|
414
|
+
new_item.mark_as_old
|
415
|
+
new_item
|
416
|
+
end
|
417
|
+
items
|
418
|
+
end
|
419
|
+
|
420
|
+
# select_by helpers
|
421
|
+
def select_all_by_(format_str, args, options) # :nodoc:
|
422
|
+
fields = format_str.to_s.sub(/^select_(all_)?by_/,'').split('_and_')
|
423
|
+
conditions = fields.map { |field| "#{field}=?" }.join(' AND ')
|
424
|
+
options[:conditions] = [conditions, *args]
|
425
|
+
select(:all, options)
|
426
|
+
end
|
427
|
+
|
428
|
+
def select_by_(format_str, args, options) # :nodoc:
|
429
|
+
options[:limit] = 1
|
430
|
+
select_all_by_(format_str, args, options).first
|
431
|
+
end
|
432
|
+
|
433
|
+
# Query
|
434
|
+
|
435
|
+
# Returns an array of query attributes.
|
436
|
+
# Query_expression must be a well formated SDB query string:
|
437
|
+
# query_attributes("['title' starts-with 'O\\'Reily'] intersection ['year' = '2007']") #=> ["title", "year"]
|
438
|
+
def query_attributes(query_expression) # :nodoc:
|
439
|
+
attrs = []
|
440
|
+
array = query_expression.scan(/['"](.*?[^\\])['"]/).flatten
|
441
|
+
until array.empty? do
|
442
|
+
attrs << array.shift # skip it's value
|
443
|
+
array.shift #
|
444
|
+
end
|
445
|
+
attrs
|
446
|
+
end
|
447
|
+
|
448
|
+
# Returns an array of [attribute_name, 'asc'|'desc']
|
449
|
+
def sort_options(sort_string)
|
450
|
+
sort_string[/['"]?(\w+)['"]? *(asc|desc)?/i]
|
451
|
+
[$1, ($2 || 'asc')]
|
452
|
+
end
|
453
|
+
|
454
|
+
# Perform a query request.
|
455
|
+
#
|
456
|
+
# Options
|
457
|
+
# :query_expression nil | string | array
|
458
|
+
# :max_number_of_items nil | integer
|
459
|
+
# :next_token nil | string
|
460
|
+
# :sort_option nil | string "name desc|asc"
|
461
|
+
#
|
462
|
+
def query(options) # :nodoc:
|
463
|
+
@next_token = options[:next_token]
|
464
|
+
query_expression = build_conditions(options[:query_expression])
|
465
|
+
# add sort_options to the query_expression
|
466
|
+
if options[:sort_option]
|
467
|
+
sort_by, sort_order = sort_options(options[:sort_option])
|
468
|
+
sort_query_expression = "['#{sort_by}' starts-with '']"
|
469
|
+
sort_by_expression = " sort '#{sort_by}' #{sort_order}"
|
470
|
+
# make query_expression to be a string (it may be null)
|
471
|
+
query_expression = query_expression.to_s
|
472
|
+
# quote from Amazon:
|
473
|
+
# The sort attribute must be present in at least one of the predicates of the query expression.
|
474
|
+
if query_expression.blank?
|
475
|
+
query_expression = sort_query_expression
|
476
|
+
elsif !query_attributes(query_expression).include?(sort_by)
|
477
|
+
query_expression += " intersection #{sort_query_expression}"
|
478
|
+
end
|
479
|
+
query_expression += sort_by_expression
|
480
|
+
end
|
481
|
+
# request items
|
482
|
+
query_result = self.connection.query(domain, query_expression, options[:max_number_of_items], @next_token)
|
294
483
|
@next_token = query_result[:next_token]
|
295
484
|
items = query_result[:items].map do |name|
|
296
485
|
new_item = self.new('id' => name)
|
297
486
|
new_item.mark_as_old
|
487
|
+
reload_if_exists(record) if options[:auto_load]
|
298
488
|
new_item
|
299
489
|
end
|
300
490
|
items
|
301
491
|
end
|
302
492
|
|
493
|
+
# reload a record unless it is nil
|
494
|
+
def reload_if_exists(record) # :nodoc:
|
495
|
+
record && record.reload
|
496
|
+
end
|
497
|
+
|
498
|
+
def reload_all_records(*list) # :nodoc:
|
499
|
+
list.flatten.each { |record| reload_if_exists(record) }
|
500
|
+
end
|
501
|
+
|
303
502
|
def find_every(options) # :nodoc:
|
304
|
-
query(
|
503
|
+
records = query( :query_expression => options[:conditions],
|
504
|
+
:max_number_of_items => options[:limit],
|
505
|
+
:next_token => options[:next_token],
|
506
|
+
:sort_option => options[:sort] || options[:order] )
|
507
|
+
options[:auto_load] ? reload_all_records(records) : records
|
305
508
|
end
|
306
509
|
|
307
510
|
def find_initial(options) # :nodoc:
|
308
511
|
options[:limit] = 1
|
309
|
-
find_every(options)
|
512
|
+
record = find_every(options).first
|
513
|
+
options[:auto_load] ? reload_all_records(record).first : record
|
310
514
|
end
|
311
515
|
|
312
516
|
def find_from_ids(args, options) # :nodoc:
|
@@ -318,15 +522,16 @@ module RightAws
|
|
318
522
|
args.each { |id| cond << "'id'=#{self.connection.escape(id)}" }
|
319
523
|
ids_cond = "[#{cond.join(' OR ')}]"
|
320
524
|
# user defined :conditions to string (if it was defined)
|
321
|
-
|
322
|
-
options[:conditions] = connection.query_expression_from_array(options[:conditions])
|
323
|
-
end
|
525
|
+
options[:conditions] = build_conditions(options[:conditions])
|
324
526
|
# join ids condition and user defined conditions
|
325
527
|
options[:conditions] = options[:conditions].blank? ? ids_cond : "#{options[:conditions]} intersection #{ids_cond}"
|
326
528
|
result = find_every(options)
|
327
529
|
# if one record was requested then return it
|
328
530
|
unless bunch_of_records_requested
|
329
|
-
result.first
|
531
|
+
record = result.first
|
532
|
+
# railse if nothing was found
|
533
|
+
raise ActiveSdbError.new("Couldn't find #{name} with ID #{args}") unless record
|
534
|
+
options[:auto_load] ? reload_all_records(record).first : record
|
330
535
|
else
|
331
536
|
# if a bunch of records was requested then return check that we found all of them
|
332
537
|
# and return as an array
|
@@ -334,35 +539,57 @@ module RightAws
|
|
334
539
|
id_list = args.map{|i| "'#{i}'"}.join(',')
|
335
540
|
raise ActiveSdbError.new("Couldn't find all #{name} with IDs (#{id_list}) (found #{result.size} results, but was looking for #{args.size})")
|
336
541
|
else
|
337
|
-
result
|
542
|
+
options[:auto_load] ? reload_all_records(result) : result
|
338
543
|
end
|
339
544
|
end
|
340
545
|
end
|
341
546
|
|
342
547
|
# find_by helpers
|
343
|
-
def find_all_by_(format_str, args,
|
548
|
+
def find_all_by_(format_str, args, options) # :nodoc:
|
344
549
|
fields = format_str.to_s.sub(/^find_(all_)?by_/,'').split('_and_')
|
345
550
|
conditions = fields.map { |field| "['#{field}'=?]" }.join(' intersection ')
|
346
|
-
|
551
|
+
options[:conditions] = [conditions, *args]
|
552
|
+
find(:all, options)
|
347
553
|
end
|
348
554
|
|
349
|
-
def find_by_(format_str, args) # :nodoc:
|
350
|
-
|
555
|
+
def find_by_(format_str, args, options) # :nodoc:
|
556
|
+
options[:limit] = 1
|
557
|
+
find_all_by_(format_str, args, options).first
|
351
558
|
end
|
352
559
|
|
560
|
+
# Misc
|
561
|
+
|
353
562
|
def method_missing(method, *args) # :nodoc:
|
354
|
-
if
|
355
|
-
|
356
|
-
|
563
|
+
if method.to_s[/^(find_all_by_|find_by_|select_all_by_|select_by_)/]
|
564
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
565
|
+
__send__($1, method, args, options)
|
566
|
+
else
|
567
|
+
super(method, *args)
|
357
568
|
end
|
358
569
|
end
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
570
|
+
|
571
|
+
def build_select(options) # :nodoc:
|
572
|
+
select = options[:select] || '*'
|
573
|
+
from = options[:from] || domain
|
574
|
+
conditions = options[:conditions] ? " WHERE #{build_conditions(options[:conditions])}" : ''
|
575
|
+
order = options[:order] ? " ORDER BY #{options[:order]}" : ''
|
576
|
+
limit = options[:limit] ? " LIMIT #{options[:limit]}" : ''
|
577
|
+
# mix sort by argument (it must present in response)
|
578
|
+
unless order.blank?
|
579
|
+
sort_by, sort_order = sort_options(options[:order])
|
580
|
+
conditions << (conditions.blank? ? " WHERE " : " AND ") << "(#{sort_by} IS NOT NULL)"
|
581
|
+
end
|
582
|
+
"SELECT #{select} FROM #{from}#{conditions}#{order}#{limit}"
|
583
|
+
end
|
584
|
+
|
585
|
+
def build_conditions(conditions) # :nodoc:
|
586
|
+
case
|
587
|
+
when conditions.is_a?(Array) then connection.query_expression_from_array(conditions)
|
588
|
+
when conditions.is_a?(Hash) then connection.query_expression_from_hash(conditions)
|
589
|
+
else conditions
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
366
593
|
end
|
367
594
|
|
368
595
|
public
|
@@ -617,7 +844,15 @@ module RightAws
|
|
617
844
|
attrs.delete('id')
|
618
845
|
unless attrs.blank?
|
619
846
|
connection.delete_attributes(domain, id, attrs)
|
620
|
-
attrs.each
|
847
|
+
attrs.each do |attribute, values|
|
848
|
+
# remove the values from the attribute
|
849
|
+
if @attributes[attribute]
|
850
|
+
@attributes[attribute] -= values
|
851
|
+
else
|
852
|
+
# if the attribute is unknown remove it from a resulting list of fixed attributes
|
853
|
+
attrs.delete(attribute)
|
854
|
+
end
|
855
|
+
end
|
621
856
|
end
|
622
857
|
attrs
|
623
858
|
end
|