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.
- data/History.txt +164 -13
- data/Manifest.txt +28 -1
- data/README.txt +12 -10
- data/Rakefile +56 -29
- data/lib/acf/right_acf_interface.rb +343 -172
- data/lib/acf/right_acf_invalidations.rb +144 -0
- data/lib/acf/right_acf_origin_access_identities.rb +230 -0
- data/lib/acf/right_acf_streaming_interface.rb +229 -0
- data/lib/acw/right_acw_interface.rb +248 -0
- data/lib/as/right_as_interface.rb +698 -0
- data/lib/awsbase/right_awsbase.rb +755 -115
- data/lib/awsbase/support.rb +2 -78
- data/lib/awsbase/version.rb +9 -0
- data/lib/ec2/right_ec2.rb +274 -1294
- data/lib/ec2/right_ec2_ebs.rb +514 -0
- data/lib/ec2/right_ec2_images.rb +444 -0
- data/lib/ec2/right_ec2_instances.rb +797 -0
- data/lib/ec2/right_ec2_monitoring.rb +70 -0
- data/lib/ec2/right_ec2_placement_groups.rb +108 -0
- data/lib/ec2/right_ec2_reserved_instances.rb +243 -0
- data/lib/ec2/right_ec2_security_groups.rb +496 -0
- data/lib/ec2/right_ec2_spot_instances.rb +422 -0
- data/lib/ec2/right_ec2_tags.rb +139 -0
- data/lib/ec2/right_ec2_vpc.rb +598 -0
- data/lib/ec2/right_ec2_vpc2.rb +382 -0
- data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
- data/lib/elb/right_elb_interface.rb +573 -0
- data/lib/emr/right_emr_interface.rb +728 -0
- data/lib/iam/right_iam_access_keys.rb +71 -0
- data/lib/iam/right_iam_groups.rb +195 -0
- data/lib/iam/right_iam_interface.rb +341 -0
- data/lib/iam/right_iam_mfa_devices.rb +67 -0
- data/lib/iam/right_iam_users.rb +251 -0
- data/lib/rds/right_rds_interface.rb +1657 -0
- data/lib/right_aws.rb +30 -13
- data/lib/route_53/right_route_53_interface.rb +641 -0
- data/lib/s3/right_s3.rb +108 -41
- data/lib/s3/right_s3_interface.rb +349 -118
- data/lib/sdb/active_sdb.rb +388 -54
- data/lib/sdb/right_sdb_interface.rb +323 -64
- data/lib/sns/right_sns_interface.rb +286 -0
- data/lib/sqs/right_sqs.rb +1 -2
- data/lib/sqs/right_sqs_gen2.rb +73 -17
- data/lib/sqs/right_sqs_gen2_interface.rb +146 -73
- data/lib/sqs/right_sqs_interface.rb +12 -22
- data/right_aws.gemspec +91 -0
- data/test/README.mdown +39 -0
- data/test/acf/test_right_acf.rb +11 -19
- data/test/awsbase/test_helper.rb +2 -0
- data/test/awsbase/test_right_awsbase.rb +11 -0
- data/test/ec2/test_right_ec2.rb +32 -1
- data/test/elb/test_helper.rb +2 -0
- data/test/elb/test_right_elb.rb +43 -0
- data/test/rds/test_helper.rb +2 -0
- data/test/rds/test_right_rds.rb +120 -0
- data/test/route_53/fixtures/a_record.xml +18 -0
- data/test/route_53/fixtures/alias_record.xml +18 -0
- data/test/route_53/test_helper.rb +2 -0
- data/test/route_53/test_right_route_53.rb +141 -0
- data/test/s3/test_right_s3.rb +176 -42
- data/test/s3/test_right_s3_stubbed.rb +6 -4
- data/test/sdb/test_active_sdb.rb +120 -19
- data/test/sdb/test_batch_put_attributes.rb +54 -0
- data/test/sdb/test_right_sdb.rb +71 -16
- data/test/sns/test_helper.rb +2 -0
- data/test/sns/test_right_sns.rb +153 -0
- data/test/sqs/test_right_sqs.rb +0 -6
- data/test/sqs/test_right_sqs_gen2.rb +104 -49
- data/test/ts_right_aws.rb +1 -0
- metadata +181 -22
data/lib/sdb/active_sdb.rb
CHANGED
@@ -21,13 +21,6 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#
|
23
23
|
|
24
|
-
begin
|
25
|
-
require 'uuidtools'
|
26
|
-
rescue LoadError => e
|
27
|
-
STDERR.puts("RightSDB Alpha requires the uuidtools gem. Run \'gem install uuidtools\' and try again.")
|
28
|
-
exit
|
29
|
-
end
|
30
|
-
|
31
24
|
module RightAws
|
32
25
|
|
33
26
|
# = RightAws::ActiveSdb -- RightScale SDB interface (alpha release)
|
@@ -39,9 +32,6 @@ module RightAws
|
|
39
32
|
# require 'right_aws'
|
40
33
|
# require 'sdb/active_sdb'
|
41
34
|
#
|
42
|
-
# Additionally, the ActiveSdb class requires the 'uuidtools' gem; this gem is not normally required by RightAws and is not installed as a
|
43
|
-
# dependency of RightAws.
|
44
|
-
#
|
45
35
|
# Simple ActiveSdb usage example:
|
46
36
|
#
|
47
37
|
# class Client < RightAws::ActiveSdb::Base
|
@@ -92,6 +82,59 @@ module RightAws
|
|
92
82
|
# # remove domain
|
93
83
|
# Client.delete_domain
|
94
84
|
#
|
85
|
+
# # Dynamic attribute accessors
|
86
|
+
#
|
87
|
+
# class KdClient < RightAws::ActiveSdb::Base
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# client = KdClient.select(:all, :order => 'expiration').first
|
91
|
+
# pp client.attributes #=>
|
92
|
+
# {"name"=>["Putin"],
|
93
|
+
# "post"=>["president"],
|
94
|
+
# "country"=>["Russia"],
|
95
|
+
# "expiration"=>["2008"],
|
96
|
+
# "id"=>"376d2e00-75b0-11dd-9557-001bfc466dd7",
|
97
|
+
# "gender"=>["male"]}
|
98
|
+
#
|
99
|
+
# pp client.name #=> ["Putin"]
|
100
|
+
# pp client.country #=> ["Russia"]
|
101
|
+
# pp client.post #=> ["president"]
|
102
|
+
#
|
103
|
+
# # Columns and simple typecasting
|
104
|
+
#
|
105
|
+
# class Person < RightAws::ActiveSdb::Base
|
106
|
+
# columns do
|
107
|
+
# name
|
108
|
+
# email
|
109
|
+
# score :Integer
|
110
|
+
# is_active :Boolean
|
111
|
+
# registered_at :DateTime
|
112
|
+
# created_at :DateTime, :default => lambda{ Time.now }
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
# Person::create( :name => 'Yetta E. Andrews', :email => 'nulla.facilisis@metus.com', :score => 100, :is_active => true, :registered_at => Time.local(2000, 1, 1) )
|
116
|
+
#
|
117
|
+
# person = Person.find_by_email 'nulla.facilisis@metus.com'
|
118
|
+
# person.reload
|
119
|
+
#
|
120
|
+
# pp person.attributes #=>
|
121
|
+
# {"name"=>["Yetta E. Andrews"],
|
122
|
+
# "created_at"=>["2010-04-02T20:51:58+0400"],
|
123
|
+
# "id"=>"0ee24946-3e60-11df-9d4c-0025b37efad0",
|
124
|
+
# "registered_at"=>["2000-01-01T00:00:00+0300"],
|
125
|
+
# "is_active"=>["T"],
|
126
|
+
# "score"=>["100"],
|
127
|
+
# "email"=>["nulla.facilisis@metus.com"]}
|
128
|
+
# pp person.name #=> "Yetta E. Andrews"
|
129
|
+
# pp person.name.class #=> String
|
130
|
+
# pp person.registered_at.to_s #=> "2000-01-01T00:00:00+03:00"
|
131
|
+
# pp person.registered_at.class #=> DateTime
|
132
|
+
# pp person.is_active #=> true
|
133
|
+
# pp person.is_active.class #=> TrueClass
|
134
|
+
# pp person.score #=> 100
|
135
|
+
# pp person.score.class #=> Fixnum
|
136
|
+
# pp person.created_at.to_s #=> "2010-04-02T20:51:58+04:00"
|
137
|
+
#
|
95
138
|
class ActiveSdb
|
96
139
|
|
97
140
|
module ActiveSdbConnect
|
@@ -106,7 +149,6 @@ module RightAws
|
|
106
149
|
# :port => 443 # Amazon service port: 80 or 443(default)
|
107
150
|
# :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
|
108
151
|
# :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
152
|
# :logger => Logger Object # Logger instance: logs to STDOUT if omitted
|
111
153
|
# :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
154
|
|
@@ -242,7 +284,31 @@ module RightAws
|
|
242
284
|
def delete_domain
|
243
285
|
connection.delete_domain(domain)
|
244
286
|
end
|
245
|
-
|
287
|
+
|
288
|
+
def columns(&block)
|
289
|
+
@columns ||= ColumnSet.new
|
290
|
+
@columns.instance_eval(&block) if block
|
291
|
+
@columns
|
292
|
+
end
|
293
|
+
|
294
|
+
def column?(col_name)
|
295
|
+
columns.include?(col_name)
|
296
|
+
end
|
297
|
+
|
298
|
+
def type_of(col_name)
|
299
|
+
columns.type_of(col_name)
|
300
|
+
end
|
301
|
+
|
302
|
+
def serialize(attribute, value)
|
303
|
+
s = serialization_for_type(type_of(attribute))
|
304
|
+
s ? s.serialize(value) : value.to_s
|
305
|
+
end
|
306
|
+
|
307
|
+
def deserialize(attribute, value)
|
308
|
+
s = serialization_for_type(type_of(attribute))
|
309
|
+
s ? s.deserialize(value) : value
|
310
|
+
end
|
311
|
+
|
246
312
|
# Perform a find request.
|
247
313
|
#
|
248
314
|
# Single record:
|
@@ -294,6 +360,8 @@ module RightAws
|
|
294
360
|
# Client.find(:first) #=> #<Client:0xb77d0d40 @attributes={"id"=>"2937601a-e45d-11dc-a75f-001bfc466dd7"}, @new_record=false>
|
295
361
|
# 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
362
|
#
|
363
|
+
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingQuery.html
|
364
|
+
#
|
297
365
|
def find(*args)
|
298
366
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
299
367
|
case args.first
|
@@ -303,12 +371,137 @@ module RightAws
|
|
303
371
|
end
|
304
372
|
end
|
305
373
|
|
374
|
+
# Perform a SQL-like select request.
|
375
|
+
#
|
376
|
+
# Single record:
|
377
|
+
#
|
378
|
+
# Client.select(:first)
|
379
|
+
# Client.select(:first, :conditions=> [ "name=? AND wife=?", "Jon", "Sandy"])
|
380
|
+
# Client.select(:first, :conditions=> { :name=>"Jon", :wife=>"Sandy" }, :select => :girfriends)
|
381
|
+
#
|
382
|
+
# Bunch of records:
|
383
|
+
#
|
384
|
+
# Client.select(:all)
|
385
|
+
# Client.select(:all, :limit => 10)
|
386
|
+
# Client.select(:all, :conditions=> [ "name=? AND 'girlfriend'=?", "Jon", "Judy"])
|
387
|
+
# Client.select(:all, :conditions=> { :name=>"Sandy" }, :limit => 3)
|
388
|
+
#
|
389
|
+
# Records by ids:
|
390
|
+
#
|
391
|
+
# Client.select('1')
|
392
|
+
# Client.select('1234987b4583475347523948')
|
393
|
+
# Client.select('1','2','3','4', :conditions=> ["toys=?", "beer"])
|
394
|
+
#
|
395
|
+
# Find helpers: RightAws::ActiveSdb::Base.select_by_... and RightAws::ActiveSdb::Base.select_all_by_...
|
396
|
+
#
|
397
|
+
# Client.select_by_name('Matias Rust')
|
398
|
+
# Client.select_by_name_and_city('Putin','Moscow')
|
399
|
+
# Client.select_by_name_and_city_and_post('Medvedev','Moscow','president')
|
400
|
+
#
|
401
|
+
# Client.select_all_by_author('G.Bush jr')
|
402
|
+
# Client.select_all_by_age_and_gender_and_ethnicity('34','male','russian')
|
403
|
+
# Client.select_all_by_gender_and_country('male', 'Russia', :order => 'name')
|
404
|
+
#
|
405
|
+
# Continue listing:
|
406
|
+
#
|
407
|
+
# # initial listing
|
408
|
+
# Client.select(:all, :limit => 10)
|
409
|
+
# # continue listing
|
410
|
+
# begin
|
411
|
+
# Client.select(:all, :limit => 10, :next_token => Client.next_token)
|
412
|
+
# end while Client.next_token
|
413
|
+
#
|
414
|
+
# Sort oder:
|
415
|
+
# If :order=>'attribute' option is specified then result response (ordered by 'attribute') will contain only items where attribute is defined (is not null).
|
416
|
+
#
|
417
|
+
# Client.select(:all) # returns all records
|
418
|
+
# Client.select(:all, :order => 'gender') # returns all records ordered by gender where gender attribute exists
|
419
|
+
# Client.select(:all, :order => 'name desc') # returns all records ordered by name in desc order where name attribute exists
|
420
|
+
#
|
421
|
+
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?UsingSelect.html
|
422
|
+
#
|
423
|
+
def select(*args)
|
424
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
425
|
+
case args.first
|
426
|
+
when :all then sql_select(options)
|
427
|
+
when :first then sql_select(options.merge(:limit => 1)).first
|
428
|
+
else select_from_ids args, options
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
def generate_id # :nodoc:
|
433
|
+
AwsUtils::generate_unique_token
|
434
|
+
end
|
435
|
+
|
306
436
|
protected
|
307
437
|
|
438
|
+
# Select
|
439
|
+
|
440
|
+
def select_from_ids(args, options) # :nodoc:
|
441
|
+
cond = []
|
442
|
+
# detect amount of records requested
|
443
|
+
bunch_of_records_requested = args.size > 1 || args.first.is_a?(Array)
|
444
|
+
# flatten ids
|
445
|
+
args = Array(args).flatten
|
446
|
+
args.each { |id| cond << "id=#{self.connection.escape(id)}" }
|
447
|
+
ids_cond = "(#{cond.join(' OR ')})"
|
448
|
+
# user defined :conditions to string (if it was defined)
|
449
|
+
options[:conditions] = build_conditions(options[:conditions])
|
450
|
+
# join ids condition and user defined conditions
|
451
|
+
options[:conditions] = options[:conditions].right_blank? ? ids_cond : "(#{options[:conditions]}) AND #{ids_cond}"
|
452
|
+
result = sql_select(options)
|
453
|
+
# if one record was requested then return it
|
454
|
+
unless bunch_of_records_requested
|
455
|
+
record = result.first
|
456
|
+
# railse if nothing was found
|
457
|
+
raise ActiveSdbError.new("Couldn't find #{name} with ID #{args}") unless record
|
458
|
+
record
|
459
|
+
else
|
460
|
+
# if a bunch of records was requested then return check that we found all of them
|
461
|
+
# and return as an array
|
462
|
+
unless args.size == result.size
|
463
|
+
id_list = args.map{|i| "'#{i}'"}.join(',')
|
464
|
+
raise ActiveSdbError.new("Couldn't find all #{name} with IDs (#{id_list}) (found #{result.size} results, but was looking for #{args.size})")
|
465
|
+
else
|
466
|
+
result
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def sql_select(options) # :nodoc:
|
472
|
+
@next_token = options[:next_token]
|
473
|
+
select_expression = build_select(options)
|
474
|
+
# request items
|
475
|
+
query_result = self.connection.select(select_expression, @next_token)
|
476
|
+
@next_token = query_result[:next_token]
|
477
|
+
items = query_result[:items].map do |hash|
|
478
|
+
id, attributes = hash.shift
|
479
|
+
new_item = self.new( attributes.merge({ 'id' => id }))
|
480
|
+
new_item.mark_as_old
|
481
|
+
new_item
|
482
|
+
end
|
483
|
+
items
|
484
|
+
end
|
485
|
+
|
486
|
+
# select_by helpers
|
487
|
+
def select_all_by_(format_str, args, options) # :nodoc:
|
488
|
+
fields = format_str.to_s.sub(/^select_(all_)?by_/,'').split('_and_')
|
489
|
+
conditions = fields.map { |field| "#{field}=?" }.join(' AND ')
|
490
|
+
options[:conditions] = [conditions, *args]
|
491
|
+
select(:all, options)
|
492
|
+
end
|
493
|
+
|
494
|
+
def select_by_(format_str, args, options) # :nodoc:
|
495
|
+
options[:limit] = 1
|
496
|
+
select_all_by_(format_str, args, options).first
|
497
|
+
end
|
498
|
+
|
499
|
+
# Query
|
500
|
+
|
308
501
|
# Returns an array of query attributes.
|
309
502
|
# Query_expression must be a well formated SDB query string:
|
310
503
|
# query_attributes("['title' starts-with 'O\\'Reily'] intersection ['year' = '2007']") #=> ["title", "year"]
|
311
|
-
def query_attributes(query_expression)
|
504
|
+
def query_attributes(query_expression) # :nodoc:
|
312
505
|
attrs = []
|
313
506
|
array = query_expression.scan(/['"](.*?[^\\])['"]/).flatten
|
314
507
|
until array.empty? do
|
@@ -334,8 +527,7 @@ module RightAws
|
|
334
527
|
#
|
335
528
|
def query(options) # :nodoc:
|
336
529
|
@next_token = options[:next_token]
|
337
|
-
query_expression = options[:query_expression]
|
338
|
-
query_expression = connection.query_expression_from_array(query_expression) if query_expression.is_a?(Array)
|
530
|
+
query_expression = build_conditions(options[:query_expression])
|
339
531
|
# add sort_options to the query_expression
|
340
532
|
if options[:sort_option]
|
341
533
|
sort_by, sort_order = sort_options(options[:sort_option])
|
@@ -345,7 +537,7 @@ module RightAws
|
|
345
537
|
query_expression = query_expression.to_s
|
346
538
|
# quote from Amazon:
|
347
539
|
# The sort attribute must be present in at least one of the predicates of the query expression.
|
348
|
-
if query_expression.
|
540
|
+
if query_expression.right_blank?
|
349
541
|
query_expression = sort_query_expression
|
350
542
|
elsif !query_attributes(query_expression).include?(sort_by)
|
351
543
|
query_expression += " intersection #{sort_query_expression}"
|
@@ -358,14 +550,19 @@ module RightAws
|
|
358
550
|
items = query_result[:items].map do |name|
|
359
551
|
new_item = self.new('id' => name)
|
360
552
|
new_item.mark_as_old
|
361
|
-
|
553
|
+
reload_if_exists(record) if options[:auto_load]
|
362
554
|
new_item
|
363
555
|
end
|
364
556
|
items
|
365
557
|
end
|
366
558
|
|
559
|
+
# reload a record unless it is nil
|
560
|
+
def reload_if_exists(record) # :nodoc:
|
561
|
+
record && record.reload
|
562
|
+
end
|
563
|
+
|
367
564
|
def reload_all_records(*list) # :nodoc:
|
368
|
-
list.flatten.each { |record| record
|
565
|
+
list.flatten.each { |record| reload_if_exists(record) }
|
369
566
|
end
|
370
567
|
|
371
568
|
def find_every(options) # :nodoc:
|
@@ -387,19 +584,20 @@ module RightAws
|
|
387
584
|
# detect amount of records requested
|
388
585
|
bunch_of_records_requested = args.size > 1 || args.first.is_a?(Array)
|
389
586
|
# flatten ids
|
390
|
-
args = args.
|
587
|
+
args = Array(args).flatten
|
391
588
|
args.each { |id| cond << "'id'=#{self.connection.escape(id)}" }
|
392
589
|
ids_cond = "[#{cond.join(' OR ')}]"
|
393
590
|
# user defined :conditions to string (if it was defined)
|
394
|
-
|
395
|
-
options[:conditions] = connection.query_expression_from_array(options[:conditions])
|
396
|
-
end
|
591
|
+
options[:conditions] = build_conditions(options[:conditions])
|
397
592
|
# join ids condition and user defined conditions
|
398
|
-
options[:conditions] = options[:conditions].
|
593
|
+
options[:conditions] = options[:conditions].right_blank? ? ids_cond : "#{options[:conditions]} intersection #{ids_cond}"
|
399
594
|
result = find_every(options)
|
400
595
|
# if one record was requested then return it
|
401
596
|
unless bunch_of_records_requested
|
402
|
-
|
597
|
+
record = result.first
|
598
|
+
# railse if nothing was found
|
599
|
+
raise ActiveSdbError.new("Couldn't find #{name} with ID #{args}") unless record
|
600
|
+
options[:auto_load] ? reload_all_records(record).first : record
|
403
601
|
else
|
404
602
|
# if a bunch of records was requested then return check that we found all of them
|
405
603
|
# and return as an array
|
@@ -425,22 +623,46 @@ module RightAws
|
|
425
623
|
find_all_by_(format_str, args, options).first
|
426
624
|
end
|
427
625
|
|
626
|
+
# Misc
|
627
|
+
|
428
628
|
def method_missing(method, *args) # :nodoc:
|
429
|
-
if method.to_s[/^(find_all_by_|find_by_)/]
|
629
|
+
if method.to_s[/^(find_all_by_|find_by_|select_all_by_|select_by_)/]
|
430
630
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
431
|
-
|
432
|
-
find_all_by_(method, args, options)
|
433
|
-
else
|
434
|
-
find_by_(method, args, options)
|
435
|
-
end
|
631
|
+
__send__($1, method, args, options)
|
436
632
|
else
|
437
633
|
super(method, *args)
|
438
634
|
end
|
439
635
|
end
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
636
|
+
|
637
|
+
def build_select(options) # :nodoc:
|
638
|
+
select = options[:select] || '*'
|
639
|
+
from = options[:from] || domain
|
640
|
+
conditions = options[:conditions] ? " WHERE #{build_conditions(options[:conditions])}" : ''
|
641
|
+
order = options[:order] ? " ORDER BY #{options[:order]}" : ''
|
642
|
+
limit = options[:limit] ? " LIMIT #{options[:limit]}" : ''
|
643
|
+
# mix sort by argument (it must present in response)
|
644
|
+
unless order.right_blank?
|
645
|
+
sort_by, sort_order = sort_options(options[:order])
|
646
|
+
conditions << (conditions.right_blank? ? " WHERE " : " AND ") << "(#{sort_by} IS NOT NULL)"
|
647
|
+
end
|
648
|
+
"SELECT #{select} FROM #{from}#{conditions}#{order}#{limit}"
|
649
|
+
end
|
650
|
+
|
651
|
+
def build_conditions(conditions) # :nodoc:
|
652
|
+
case
|
653
|
+
when conditions.is_a?(Array) then connection.query_expression_from_array(conditions)
|
654
|
+
when conditions.is_a?(Hash) then connection.query_expression_from_hash(conditions)
|
655
|
+
else conditions
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
def serialization_for_type(type)
|
660
|
+
@serializations ||= {}
|
661
|
+
unless @serializations.has_key? type
|
662
|
+
@serializations[type] = ::RightAws::ActiveSdb.const_get("#{type}Serialization") rescue false
|
663
|
+
end
|
664
|
+
@serializations[type]
|
665
|
+
end
|
444
666
|
end
|
445
667
|
|
446
668
|
public
|
@@ -508,11 +730,15 @@ module RightAws
|
|
508
730
|
def attributes=(attrs)
|
509
731
|
old_id = @attributes['id']
|
510
732
|
@attributes = uniq_values(attrs)
|
511
|
-
@attributes['id'] = old_id if @attributes['id'].
|
733
|
+
@attributes['id'] = old_id if @attributes['id'].right_blank? && !old_id.right_blank?
|
512
734
|
self.attributes
|
513
735
|
end
|
514
736
|
|
515
|
-
def
|
737
|
+
def columns
|
738
|
+
self.class.columns
|
739
|
+
end
|
740
|
+
|
741
|
+
def connection
|
516
742
|
self.class.connection
|
517
743
|
end
|
518
744
|
|
@@ -526,7 +752,8 @@ module RightAws
|
|
526
752
|
# puts item['Cat'].inspect #=> ["Jons socks", "clew", "mice"]
|
527
753
|
#
|
528
754
|
def [](attribute)
|
529
|
-
@attributes[attribute.to_s]
|
755
|
+
raw = @attributes[attribute.to_s]
|
756
|
+
self.class.column?(attribute) && raw ? self.class.deserialize(attribute, raw.first) : raw
|
530
757
|
end
|
531
758
|
|
532
759
|
# Updates the attribute identified by +attribute+ with the specified +values+.
|
@@ -537,7 +764,14 @@ module RightAws
|
|
537
764
|
#
|
538
765
|
def []=(attribute, values)
|
539
766
|
attribute = attribute.to_s
|
540
|
-
@attributes[attribute] =
|
767
|
+
@attributes[attribute] = case
|
768
|
+
when attribute == 'id'
|
769
|
+
values.to_s
|
770
|
+
when self.class.column?(attribute)
|
771
|
+
self.class.serialize(attribute, values)
|
772
|
+
else
|
773
|
+
Array(values).uniq
|
774
|
+
end
|
541
775
|
end
|
542
776
|
|
543
777
|
# Reload attributes from SDB. Replaces in-memory attributes.
|
@@ -550,7 +784,7 @@ module RightAws
|
|
550
784
|
old_id = id
|
551
785
|
attrs = connection.get_attributes(domain, id)[:attributes]
|
552
786
|
@attributes = {}
|
553
|
-
unless attrs.
|
787
|
+
unless attrs.right_blank?
|
554
788
|
attrs.each { |attribute, values| @attributes[attribute] = values }
|
555
789
|
@attributes['id'] = old_id
|
556
790
|
end
|
@@ -576,7 +810,7 @@ module RightAws
|
|
576
810
|
attrs_list.flatten.uniq.each do |attribute|
|
577
811
|
attribute = attribute.to_s
|
578
812
|
values = connection.get_attributes(domain, id, attribute)[:attributes][attribute]
|
579
|
-
unless values.
|
813
|
+
unless values.right_blank?
|
580
814
|
@attributes[attribute] = result[attribute] = values
|
581
815
|
else
|
582
816
|
@attributes.delete(attribute)
|
@@ -606,7 +840,7 @@ module RightAws
|
|
606
840
|
prepare_for_update
|
607
841
|
attrs = @attributes.dup
|
608
842
|
attrs.delete('id')
|
609
|
-
connection.put_attributes(domain, id, attrs) unless attrs.
|
843
|
+
connection.put_attributes(domain, id, attrs) unless attrs.right_blank?
|
610
844
|
connection.put_attributes(domain, id, { 'id' => id }, :replace)
|
611
845
|
mark_as_old
|
612
846
|
@attributes
|
@@ -622,10 +856,10 @@ module RightAws
|
|
622
856
|
prepare_for_update
|
623
857
|
# if 'id' is present in attrs hash:
|
624
858
|
# replace internal 'id' attribute and remove it from the attributes to be sent
|
625
|
-
@attributes['id'] = attrs['id'] unless attrs['id'].
|
859
|
+
@attributes['id'] = attrs['id'] unless attrs['id'].right_blank?
|
626
860
|
attrs.delete('id')
|
627
861
|
# add new values to all attributes from list
|
628
|
-
connection.put_attributes(domain, id, attrs) unless attrs.
|
862
|
+
connection.put_attributes(domain, id, attrs) unless attrs.right_blank?
|
629
863
|
connection.put_attributes(domain, id, { 'id' => id }, :replace)
|
630
864
|
attrs.each do |attribute, values|
|
631
865
|
@attributes[attribute] ||= []
|
@@ -669,12 +903,12 @@ module RightAws
|
|
669
903
|
prepare_for_update
|
670
904
|
attrs = uniq_values(attrs)
|
671
905
|
# if 'id' is present in attrs hash then replace internal 'id' attribute
|
672
|
-
unless attrs['id'].
|
906
|
+
unless attrs['id'].right_blank?
|
673
907
|
@attributes['id'] = attrs['id']
|
674
908
|
else
|
675
909
|
attrs['id'] = id
|
676
910
|
end
|
677
|
-
connection.put_attributes(domain, id, attrs, :replace) unless attrs.
|
911
|
+
connection.put_attributes(domain, id, attrs, :replace) unless attrs.right_blank?
|
678
912
|
attrs.each { |attribute, values| attrs[attribute] = values }
|
679
913
|
mark_as_old
|
680
914
|
attrs
|
@@ -693,9 +927,17 @@ module RightAws
|
|
693
927
|
raise_on_id_absence
|
694
928
|
attrs = uniq_values(attrs)
|
695
929
|
attrs.delete('id')
|
696
|
-
unless attrs.
|
930
|
+
unless attrs.right_blank?
|
697
931
|
connection.delete_attributes(domain, id, attrs)
|
698
|
-
attrs.each
|
932
|
+
attrs.each do |attribute, values|
|
933
|
+
# remove the values from the attribute
|
934
|
+
if @attributes[attribute]
|
935
|
+
@attributes[attribute] -= values
|
936
|
+
else
|
937
|
+
# if the attribute is unknown remove it from a resulting list of fixed attributes
|
938
|
+
attrs.delete(attribute)
|
939
|
+
end
|
940
|
+
end
|
699
941
|
end
|
700
942
|
attrs
|
701
943
|
end
|
@@ -714,7 +956,7 @@ module RightAws
|
|
714
956
|
raise_on_id_absence
|
715
957
|
attrs_list = attrs_list.flatten.map{ |attribute| attribute.to_s }
|
716
958
|
attrs_list.delete('id')
|
717
|
-
unless attrs_list.
|
959
|
+
unless attrs_list.right_blank?
|
718
960
|
connection.delete_attributes(domain, id, attrs_list)
|
719
961
|
attrs_list.each { |attribute| @attributes.delete(attribute) }
|
720
962
|
end
|
@@ -749,25 +991,117 @@ module RightAws
|
|
749
991
|
@new_record = false
|
750
992
|
end
|
751
993
|
|
752
|
-
|
753
|
-
|
994
|
+
# support accessing attribute values via method call
|
995
|
+
def method_missing(method_sym, *args)
|
996
|
+
method_name = method_sym.to_s
|
997
|
+
setter = method_name[-1,1] == '='
|
998
|
+
method_name.chop! if setter
|
999
|
+
|
1000
|
+
if @attributes.has_key?(method_name) || self.class.column?(method_name)
|
1001
|
+
setter ? self[method_name] = args.first : self[method_name]
|
1002
|
+
else
|
1003
|
+
super
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
private
|
1008
|
+
|
754
1009
|
def raise_on_id_absence
|
755
1010
|
raise ActiveSdbError.new('Unknown record id') unless id
|
756
1011
|
end
|
757
1012
|
|
758
1013
|
def prepare_for_update
|
759
|
-
@attributes['id'] = self.class.generate_id if @attributes['id'].
|
1014
|
+
@attributes['id'] = self.class.generate_id if @attributes['id'].right_blank?
|
1015
|
+
columns.all.each do |col_name|
|
1016
|
+
self[col_name] ||= columns.default(col_name)
|
1017
|
+
end
|
760
1018
|
end
|
761
1019
|
|
762
1020
|
def uniq_values(attributes=nil) # :nodoc:
|
763
1021
|
attrs = {}
|
764
1022
|
attributes.each do |attribute, values|
|
765
1023
|
attribute = attribute.to_s
|
766
|
-
attrs[attribute] =
|
767
|
-
|
1024
|
+
attrs[attribute] = case
|
1025
|
+
when attribute == 'id'
|
1026
|
+
values.to_s
|
1027
|
+
when self.class.column?(attribute)
|
1028
|
+
values.is_a?(String) ? values : self.class.serialize(attribute, values)
|
1029
|
+
else
|
1030
|
+
Array(values).uniq
|
1031
|
+
end
|
1032
|
+
attrs.delete(attribute) if values.right_blank?
|
768
1033
|
end
|
769
1034
|
attrs
|
770
1035
|
end
|
771
1036
|
end
|
1037
|
+
|
1038
|
+
class ColumnSet
|
1039
|
+
attr_accessor :columns
|
1040
|
+
def initialize
|
1041
|
+
@columns = {}
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
def all
|
1045
|
+
@columns.keys
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def column(col_name)
|
1049
|
+
@columns[col_name.to_s]
|
1050
|
+
end
|
1051
|
+
alias_method :include?, :column
|
1052
|
+
|
1053
|
+
def type_of(col_name)
|
1054
|
+
column(col_name) && column(col_name)[:type]
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def default(col_name)
|
1058
|
+
return nil unless include?(col_name)
|
1059
|
+
default = column(col_name)[:default]
|
1060
|
+
default.respond_to?(:call) ? default.call : default
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
def method_missing(method_sym, *args)
|
1064
|
+
data_type = args.shift || :String
|
1065
|
+
options = args.shift || {}
|
1066
|
+
@columns[method_sym.to_s] = options.merge( :type => data_type )
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
class DateTimeSerialization
|
1071
|
+
class << self
|
1072
|
+
def serialize(date)
|
1073
|
+
date.strftime('%Y-%m-%dT%H:%M:%S%z')
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
def deserialize(string)
|
1077
|
+
r = DateTime.parse(string) rescue nil
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
class BooleanSerialization
|
1083
|
+
class << self
|
1084
|
+
def serialize(boolean)
|
1085
|
+
boolean ? 'T' : 'F'
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
def deserialize(string)
|
1089
|
+
string == 'T'
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
class IntegerSerialization
|
1095
|
+
class << self
|
1096
|
+
def serialize(int)
|
1097
|
+
int.to_s
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def deserialize(string)
|
1101
|
+
string.to_i
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
|
772
1106
|
end
|
773
|
-
end
|
1107
|
+
end
|