simple_record 2.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +27 -1
- data/lib/simple_record.rb +165 -91
- data/lib/simple_record/active_sdb.rb +1 -1
- data/lib/simple_record/attributes.rb +3 -3
- data/lib/simple_record/callbacks.rb +45 -17
- data/lib/simple_record/sharding.rb +238 -238
- data/lib/simple_record/translations.rb +223 -223
- data/lib/simple_record/validations.rb +69 -0
- data/test/my_model.rb +71 -35
- data/test/my_sharded_model.rb +25 -20
- data/test/my_simple_model.rb +13 -0
- data/test/test_shards.rb +122 -119
- data/test/test_simple_record.rb +5 -22
- data/test/test_validations.rb +45 -0
- metadata +42 -53
- data/lib/simple_record/rails2.rb +0 -30
data/README.markdown
CHANGED
@@ -70,6 +70,11 @@ This is required because SimpleDB only has strings so SimpleRecord needs to know
|
|
70
70
|
has_booleans :is_nerd
|
71
71
|
end
|
72
72
|
|
73
|
+
### Multi-value attributes
|
74
|
+
|
75
|
+
SimpleDB supports having multiple values for the same attribute so to use this feature, simply set an attribute to an
|
76
|
+
array of values.
|
77
|
+
|
73
78
|
### belongs_to
|
74
79
|
|
75
80
|
Creates a many-to-one relationship. Can only have one per belongs_to call.
|
@@ -207,13 +212,34 @@ Use per_thread connection mode and close the connection after each request.
|
|
207
212
|
|
208
213
|
### Disable ActiveRecord so you don't have to setup another database
|
209
214
|
|
210
|
-
|
215
|
+
#### Rails 2
|
216
|
+
|
217
|
+
This is most helpful on windows so Rails doesn't need sqlite or mysql gems/drivers installed which are painful to install on windows.
|
218
|
+
In environment.rb, add 'config.frameworks -= [ :active_record ]', so it should look something like:
|
211
219
|
|
212
220
|
Rails::Initializer.run do |config|
|
213
221
|
config.frameworks -= [ :active_record ]
|
214
222
|
....
|
215
223
|
end
|
216
224
|
|
225
|
+
#### Rails 3
|
226
|
+
|
227
|
+
At the top of application.rb, comment out `require 'rails/all` and add the following:
|
228
|
+
|
229
|
+
#require 'rails/all'
|
230
|
+
%w(
|
231
|
+
action_controller
|
232
|
+
action_mailer
|
233
|
+
active_resource
|
234
|
+
rails/test_unit
|
235
|
+
).each do |framework|
|
236
|
+
begin
|
237
|
+
require "#{framework}/railtie"
|
238
|
+
rescue LoadError
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
This is the same as rails/all minus active_record.
|
217
243
|
|
218
244
|
## Large Objects (LOBS)
|
219
245
|
|
data/lib/simple_record.rb
CHANGED
@@ -28,6 +28,13 @@ require 'aws'
|
|
28
28
|
require 'base64'
|
29
29
|
require 'active_support'
|
30
30
|
require 'active_support/core_ext'
|
31
|
+
begin
|
32
|
+
# comment out line below to test rails2 validations
|
33
|
+
require 'active_model'
|
34
|
+
rescue LoadError => ex
|
35
|
+
puts "ActiveModel not available, falling back."
|
36
|
+
end
|
37
|
+
require File.expand_path(File.dirname(__FILE__) + "/simple_record/validations")
|
31
38
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/attributes")
|
32
39
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/active_sdb")
|
33
40
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/callbacks")
|
@@ -36,7 +43,6 @@ require File.expand_path(File.dirname(__FILE__) + "/simple_record/errors")
|
|
36
43
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/json")
|
37
44
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/logging")
|
38
45
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/password")
|
39
|
-
require File.expand_path(File.dirname(__FILE__) + "/simple_record/rails2")
|
40
46
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/results_array")
|
41
47
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/stats")
|
42
48
|
require File.expand_path(File.dirname(__FILE__) + "/simple_record/translations")
|
@@ -170,14 +176,28 @@ module SimpleRecord
|
|
170
176
|
|
171
177
|
|
172
178
|
# puts 'Is ActiveModel defined? ' + defined?(ActiveModel).inspect
|
179
|
+
|
180
|
+
|
173
181
|
if defined?(ActiveModel)
|
182
|
+
@@active_model = true
|
174
183
|
extend ActiveModel::Naming
|
175
184
|
include ActiveModel::Conversion
|
176
185
|
include ActiveModel::Validations
|
186
|
+
extend ActiveModel::Callbacks # for ActiveRecord like callbacks
|
187
|
+
include ActiveModel::Validations::Callbacks
|
188
|
+
define_model_callbacks :save, :create, :update, :destroy
|
189
|
+
include SimpleRecord::Callbacks3
|
190
|
+
alias_method :am_valid?, :valid?
|
191
|
+
|
192
|
+
|
177
193
|
else
|
194
|
+
@@active_model = false
|
195
|
+
puts "using rails2 validations."
|
178
196
|
attr_accessor :errors
|
179
|
-
include SimpleRecord::
|
197
|
+
include SimpleRecord::Callbacks
|
180
198
|
end
|
199
|
+
include SimpleRecord::Validations
|
200
|
+
|
181
201
|
|
182
202
|
include SimpleRecord::Translations
|
183
203
|
# include SimpleRecord::Attributes
|
@@ -185,7 +205,6 @@ module SimpleRecord
|
|
185
205
|
include SimpleRecord::Attributes
|
186
206
|
extend SimpleRecord::Sharding::ClassMethods
|
187
207
|
include SimpleRecord::Sharding
|
188
|
-
include SimpleRecord::Callbacks
|
189
208
|
include SimpleRecord::Json
|
190
209
|
include SimpleRecord::Logging
|
191
210
|
extend SimpleRecord::Logging::ClassMethods
|
@@ -362,11 +381,10 @@ module SimpleRecord
|
|
362
381
|
end
|
363
382
|
|
364
383
|
def clear_errors
|
365
|
-
|
366
|
-
if not (defined?(ActiveModel))
|
367
|
-
@errors=SimpleRecord_errors.new
|
368
|
-
else
|
384
|
+
if defined?(ActiveModel)
|
369
385
|
@errors = ActiveModel::Errors.new(self)
|
386
|
+
else
|
387
|
+
@errors=SimpleRecord_errors.new
|
370
388
|
end
|
371
389
|
end
|
372
390
|
|
@@ -398,9 +416,6 @@ module SimpleRecord
|
|
398
416
|
self.updated
|
399
417
|
end
|
400
418
|
|
401
|
-
def read_attribute_for_validation(key)
|
402
|
-
@attributes[key.to_s]
|
403
|
-
end
|
404
419
|
|
405
420
|
def cache_store
|
406
421
|
@@cache_store
|
@@ -429,8 +444,9 @@ module SimpleRecord
|
|
429
444
|
# - :dirty => true - Will only store attributes that were modified. To make it save regardless and have it update the :updated value, include this and set it to false.
|
430
445
|
# - :domain => Explicitly define domain to use.
|
431
446
|
#
|
447
|
+
|
432
448
|
def save(options={})
|
433
|
-
|
449
|
+
puts 'SAVING: ' + self.inspect if SimpleRecord.logging?
|
434
450
|
# todo: Clean out undefined values in @attributes (in case someone set the attributes hash with values that they hadn't defined)
|
435
451
|
clear_errors
|
436
452
|
# todo: decide whether this should go before pre_save or after pre_save? pre_save dirties "updated" and perhaps other items due to callbacks
|
@@ -441,6 +457,7 @@ module SimpleRecord
|
|
441
457
|
is_create = self[:id].nil?
|
442
458
|
ok = pre_save(options) # Validates and sets ID
|
443
459
|
if ok
|
460
|
+
# puts 'ok'
|
444
461
|
begin
|
445
462
|
dirty = @dirty
|
446
463
|
# puts 'dirty before=' + @dirty.inspect
|
@@ -449,48 +466,119 @@ module SimpleRecord
|
|
449
466
|
return true if @dirty.size == 0 # This should probably never happen because after pre_save, created/updated dates are changed
|
450
467
|
options[:dirty_atts] = @dirty
|
451
468
|
end
|
452
|
-
to_delete
|
453
|
-
|
469
|
+
to_delete = get_atts_to_delete
|
470
|
+
|
454
471
|
|
455
472
|
if self.class.is_sharded?
|
456
473
|
options[:domain] = sharded_domain
|
457
474
|
end
|
458
475
|
|
459
|
-
if
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
after_save_cleanup
|
464
|
-
if (is_create ? run_after_create : run_after_update) && run_after_save
|
465
|
-
# puts 'all good?'
|
466
|
-
return true
|
467
|
-
else
|
468
|
-
return false
|
469
|
-
end
|
476
|
+
if @@active_model
|
477
|
+
x = save_super(dirty, is_create, options, to_delete)
|
478
|
+
# puts 'save_super result = ' + x.to_s
|
479
|
+
return x
|
470
480
|
else
|
471
|
-
|
481
|
+
# puts 'not activemodel callbacks'
|
482
|
+
return save_super(dirty, is_create, options, to_delete)
|
472
483
|
end
|
473
484
|
rescue Aws::AwsError => ex
|
474
|
-
# puts "RESCUED in save: " + $!
|
475
|
-
# Domain is created in aws lib now using :create_domain=>true
|
476
|
-
# if (domain_ok(ex, options))
|
477
|
-
# if !@create_domain_called
|
478
|
-
# @create_domain_called = true
|
479
|
-
# save(options)
|
480
|
-
# else
|
481
|
-
# raise $!
|
482
|
-
# end
|
483
|
-
# else
|
484
|
-
# raise $!
|
485
|
-
# end
|
486
485
|
raise ex
|
487
486
|
end
|
488
487
|
else
|
489
|
-
|
488
|
+
# puts 'returning false'
|
490
489
|
return false
|
491
490
|
end
|
492
491
|
end
|
493
492
|
|
493
|
+
if @@active_model
|
494
|
+
alias_method :old_save, :save
|
495
|
+
|
496
|
+
def save(options={})
|
497
|
+
# puts 'extended save'
|
498
|
+
x = create_or_update
|
499
|
+
# puts 'save x=' + x.to_s
|
500
|
+
x
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def create_or_update #:nodoc:
|
505
|
+
# puts 'create_or_update'
|
506
|
+
ret = true
|
507
|
+
_run_save_callbacks do
|
508
|
+
result = new_record? ? create : update
|
509
|
+
# puts 'save_callbacks result=' + result.inspect
|
510
|
+
ret = result
|
511
|
+
end
|
512
|
+
ret
|
513
|
+
end
|
514
|
+
|
515
|
+
def create #:nodoc:
|
516
|
+
puts '3 create'
|
517
|
+
ret = true
|
518
|
+
_run_create_callbacks do
|
519
|
+
x = old_save
|
520
|
+
# puts 'create old_save result=' + x.to_s
|
521
|
+
ret = x
|
522
|
+
end
|
523
|
+
ret
|
524
|
+
end
|
525
|
+
|
526
|
+
#
|
527
|
+
def update(*) #:nodoc:
|
528
|
+
puts '3 update'
|
529
|
+
ret = true
|
530
|
+
_run_update_callbacks do
|
531
|
+
x = old_save
|
532
|
+
# puts 'update old_save result=' + x.to_s
|
533
|
+
ret = x
|
534
|
+
end
|
535
|
+
ret
|
536
|
+
end
|
537
|
+
|
538
|
+
|
539
|
+
def save!(options={})
|
540
|
+
save(options) || raise(RecordNotSaved.new(self))
|
541
|
+
end
|
542
|
+
|
543
|
+
# this is a bit wonky, save! should call this, not sure why it's here.
|
544
|
+
def save_with_validation!(options={})
|
545
|
+
save!
|
546
|
+
end
|
547
|
+
|
548
|
+
def self.create(attributes={})
|
549
|
+
# puts "About to create in domain #{domain}"
|
550
|
+
super
|
551
|
+
end
|
552
|
+
|
553
|
+
def self.create!(attributes={})
|
554
|
+
item = self.new(attributes)
|
555
|
+
item.save!
|
556
|
+
item
|
557
|
+
end
|
558
|
+
|
559
|
+
|
560
|
+
def save_super(dirty, is_create, options, to_delete)
|
561
|
+
SimpleRecord.stats.saves += 1
|
562
|
+
if save2(options)
|
563
|
+
self.class.cache_results(self)
|
564
|
+
delete_niled(to_delete)
|
565
|
+
save_lobs(dirty)
|
566
|
+
after_save_cleanup
|
567
|
+
unless @@active_model
|
568
|
+
if (is_create ? run_after_create : run_after_update) && run_after_save
|
569
|
+
# puts 'all good?'
|
570
|
+
return true
|
571
|
+
else
|
572
|
+
return false
|
573
|
+
end
|
574
|
+
end
|
575
|
+
return true
|
576
|
+
else
|
577
|
+
return false
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
|
494
582
|
def save_lobs(dirty=nil)
|
495
583
|
# puts 'dirty.inspect=' + dirty.inspect
|
496
584
|
dirty = @dirty if dirty.nil?
|
@@ -600,26 +688,6 @@ module SimpleRecord
|
|
600
688
|
"lobs/#{self.id}_single_clob"
|
601
689
|
end
|
602
690
|
|
603
|
-
def save!(options={})
|
604
|
-
save(options) || raise(RecordNotSaved.new(nil, self))
|
605
|
-
end
|
606
|
-
|
607
|
-
# this is a bit wonky, save! should call this, not sure why it's here.
|
608
|
-
def save_with_validation!(options={})
|
609
|
-
save!
|
610
|
-
end
|
611
|
-
|
612
|
-
def self.create(attributes={})
|
613
|
-
# puts "About to create in domain #{domain}"
|
614
|
-
super
|
615
|
-
end
|
616
|
-
|
617
|
-
def self.create!(attributes={})
|
618
|
-
item = self.new(attributes)
|
619
|
-
item.save!
|
620
|
-
item
|
621
|
-
end
|
622
|
-
|
623
691
|
|
624
692
|
def self.get_encryption_key()
|
625
693
|
key = SimpleRecord.options[:encryption_key]
|
@@ -630,28 +698,20 @@ module SimpleRecord
|
|
630
698
|
return key
|
631
699
|
end
|
632
700
|
|
633
|
-
def validate
|
634
|
-
true
|
635
|
-
end
|
636
|
-
|
637
|
-
def validate_on_create
|
638
|
-
true
|
639
|
-
end
|
640
|
-
|
641
|
-
def validate_on_update
|
642
|
-
true
|
643
|
-
end
|
644
|
-
|
645
|
-
|
646
701
|
def pre_save(options)
|
647
702
|
|
703
|
+
|
704
|
+
ok = true
|
648
705
|
is_create = self[:id].nil?
|
649
|
-
|
650
|
-
|
706
|
+
unless @@active_model
|
707
|
+
ok = run_before_validation && (is_create ? run_before_validation_on_create : run_before_validation_on_update)
|
708
|
+
return false unless ok
|
709
|
+
end
|
651
710
|
|
652
711
|
# validate()
|
653
712
|
# is_create ? validate_on_create : validate_on_update
|
654
713
|
if !valid?
|
714
|
+
puts 'not valid'
|
655
715
|
return false
|
656
716
|
end
|
657
717
|
#
|
@@ -661,23 +721,26 @@ module SimpleRecord
|
|
661
721
|
# return false
|
662
722
|
# end
|
663
723
|
|
664
|
-
|
665
|
-
|
724
|
+
unless @@active_model
|
725
|
+
ok = run_after_validation && (is_create ? run_after_validation_on_create : run_after_validation_on_update)
|
726
|
+
return false unless ok
|
727
|
+
end
|
666
728
|
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
729
|
+
# Now for callbacks
|
730
|
+
unless @@active_model
|
731
|
+
ok = respond_to?('before_save') ? before_save : true
|
732
|
+
if ok
|
733
|
+
if is_create && respond_to?('before_create')
|
734
|
+
ok = before_create
|
735
|
+
elsif !is_create && respond_to?('before_update')
|
736
|
+
ok = before_update
|
737
|
+
end
|
673
738
|
end
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
# Now translate all fields into SimpleDB friendly strings
|
680
|
-
# convert_all_atts_to_sdb()
|
739
|
+
if ok
|
740
|
+
ok = run_before_save && (is_create ? run_before_create : run_before_update)
|
741
|
+
end
|
742
|
+
else
|
743
|
+
|
681
744
|
end
|
682
745
|
prepare_for_update
|
683
746
|
ok
|
@@ -779,10 +842,15 @@ module SimpleRecord
|
|
779
842
|
end
|
780
843
|
|
781
844
|
def destroy
|
782
|
-
|
845
|
+
if @@active_model
|
846
|
+
_run_destroy_callbacks do
|
847
|
+
delete
|
848
|
+
end
|
849
|
+
else
|
850
|
+
return run_before_destroy && delete && run_after_destroy
|
851
|
+
end
|
783
852
|
end
|
784
853
|
|
785
|
-
|
786
854
|
def delete_niled(to_delete)
|
787
855
|
# puts 'to_delete=' + to_delete.inspect
|
788
856
|
if to_delete.size > 0
|
@@ -861,6 +929,11 @@ module SimpleRecord
|
|
861
929
|
if params.size > 1
|
862
930
|
options = params[1]
|
863
931
|
end
|
932
|
+
conditions = options[:conditions]
|
933
|
+
if conditions && conditions.is_a?(String)
|
934
|
+
conditions = [conditions]
|
935
|
+
options[:conditions] = conditions
|
936
|
+
end
|
864
937
|
|
865
938
|
if !options[:shard_find] && is_sharded?
|
866
939
|
# then break off and get results across all shards
|
@@ -958,7 +1031,8 @@ module SimpleRecord
|
|
958
1031
|
def self.convert_condition_params(options)
|
959
1032
|
return if options.nil?
|
960
1033
|
conditions = options[:conditions]
|
961
|
-
if
|
1034
|
+
return if conditions.nil?
|
1035
|
+
if conditions.size > 1
|
962
1036
|
# all after first are values
|
963
1037
|
conditions.collect! { |x|
|
964
1038
|
Translations.pad_and_offset(x)
|
@@ -856,7 +856,7 @@ module SimpleRecord
|
|
856
856
|
# - :except => Array of attributes to NOT save
|
857
857
|
#
|
858
858
|
# compare to +put+ method
|
859
|
-
def
|
859
|
+
def save2(options={})
|
860
860
|
options[:create_domain] = true if options[:create_domain].nil?
|
861
861
|
pre_save2
|
862
862
|
atts_to_save = @attributes.dup
|
@@ -346,14 +346,14 @@ module SimpleRecord
|
|
346
346
|
begin
|
347
347
|
single_clob = s3_bucket(false, :s3_bucket=>:new).get(single_clob_id)
|
348
348
|
single_clob = JSON.parse(single_clob)
|
349
|
-
puts "single_clob=" + single_clob.inspect
|
349
|
+
# puts "single_clob=" + single_clob.inspect
|
350
350
|
single_clob.each_pair do |name2,val|
|
351
351
|
@lobs[name2.to_sym] = val
|
352
352
|
end
|
353
353
|
ret = @lobs[name]
|
354
354
|
SimpleRecord.stats.s3_gets += 1
|
355
355
|
rescue Aws::AwsError => ex
|
356
|
-
if ex.include?
|
356
|
+
if ex.include?(/NoSuchKey/) || ex.include?(/NoSuchBucket/)
|
357
357
|
ret = nil
|
358
358
|
else
|
359
359
|
raise ex
|
@@ -365,7 +365,7 @@ module SimpleRecord
|
|
365
365
|
# puts 'got from s3 ' + ret.inspect
|
366
366
|
SimpleRecord.stats.s3_gets += 1
|
367
367
|
rescue Aws::AwsError => ex
|
368
|
-
if ex.include?
|
368
|
+
if ex.include?(/NoSuchKey/) || ex.include?(/NoSuchBucket/)
|
369
369
|
ret = nil
|
370
370
|
else
|
371
371
|
raise ex
|