simple_record 2.0.5 → 2.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/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
|