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
@@ -0,0 +1,69 @@
|
|
1
|
+
# This is actually still used to continue support for this.
|
2
|
+
# ActiveModel does not work the same way so need to continue using this, will change name.
|
3
|
+
|
4
|
+
module SimpleRecord
|
5
|
+
module Validations
|
6
|
+
|
7
|
+
# if defined?(:valid?) # from ActiveModel
|
8
|
+
# alias_method :am_valid?, :valid?
|
9
|
+
# end
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
puts 'Validations included ' + base.inspect
|
13
|
+
# if defined?(ActiveModel)
|
14
|
+
# base.class_eval do
|
15
|
+
# alias_method :am_valid?, :valid?
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
puts 'in rails2 valid?'
|
22
|
+
errors.clear
|
23
|
+
|
24
|
+
if defined?(:am_valid?)
|
25
|
+
# And now ActiveModel validations too
|
26
|
+
am_valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
# run_callbacks(:validate)
|
30
|
+
validate
|
31
|
+
|
32
|
+
|
33
|
+
if new_record?
|
34
|
+
# run_callbacks(:validate_on_create)
|
35
|
+
validate_on_create
|
36
|
+
else
|
37
|
+
# run_callbacks(:validate_on_update)
|
38
|
+
validate_on_update
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
errors.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
def invalid?
|
46
|
+
!valid?
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def read_attribute_for_validation(key)
|
51
|
+
@attributes[key.to_s]
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_on_create
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_on_update
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
data/test/my_model.rb
CHANGED
@@ -1,60 +1,96 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
|
2
2
|
require_relative 'my_base_model'
|
3
|
+
require_relative 'my_sharded_model'
|
3
4
|
|
4
5
|
class MyModel < MyBaseModel
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
has_strings :name, :nickname, :s1, :s2
|
8
|
+
has_ints :age, :save_count
|
9
|
+
has_booleans :cool
|
10
|
+
has_dates :birthday, :date1, :date2, :date3
|
10
11
|
|
11
|
-
|
12
|
+
# validates_presence_of :name
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
# validate :validate
|
15
|
+
# before_create :validate_on_create
|
16
|
+
# before_update :validate_on_update
|
15
17
|
|
16
|
-
|
18
|
+
belongs_to :my_sharded_model
|
17
19
|
|
18
|
-
|
19
|
-
self.nickname = name if self.nickname.blank?
|
20
|
-
end
|
20
|
+
has_clobs :clob1, :clob2
|
21
21
|
|
22
|
-
|
23
|
-
# puts 'save_count=' + save_count.to_s
|
24
|
-
if save_count.nil?
|
25
|
-
self.save_count = 1
|
26
|
-
else
|
27
|
-
self.save_count += 1
|
28
|
-
end
|
29
|
-
# puts 'save_count=' + self.save_count.to_s
|
30
|
-
end
|
22
|
+
attr_accessor :attr_before_save, :attr_after_save, :attr_before_create, :attr_after_create
|
31
23
|
|
32
|
-
|
33
|
-
|
34
|
-
|
24
|
+
#callbacks
|
25
|
+
before_create :set_nickname
|
26
|
+
after_create :after_create
|
27
|
+
|
28
|
+
before_save :before_save
|
29
|
+
|
30
|
+
after_save :after_save
|
31
|
+
|
32
|
+
def set_nickname
|
33
|
+
puts 'before_create set nickname'
|
34
|
+
@attr_before_create = true
|
35
|
+
self.nickname = name if self.nickname.blank?
|
36
|
+
end
|
37
|
+
|
38
|
+
def before_save
|
39
|
+
puts 'before_save'
|
40
|
+
@attr_before_save = true
|
41
|
+
end
|
35
42
|
|
36
|
-
|
37
|
-
|
43
|
+
def after_create
|
44
|
+
puts 'after_create'
|
45
|
+
@attr_after_create = true
|
46
|
+
end
|
47
|
+
|
48
|
+
def after_save
|
49
|
+
puts "after_save"
|
50
|
+
@attr_after_save = true
|
51
|
+
bump_save_count
|
52
|
+
end
|
53
|
+
|
54
|
+
def bump_save_count
|
55
|
+
puts 'after_save bump save_count=' + save_count.to_s
|
56
|
+
if save_count.nil?
|
57
|
+
self.save_count = 1
|
58
|
+
else
|
59
|
+
self.save_count += 1
|
38
60
|
end
|
61
|
+
# puts 'save_count=' + self.save_count.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate
|
65
|
+
puts 'MyModel.validate'
|
66
|
+
errors.add("name", "can't be empty.") if name.blank?
|
67
|
+
# errors.add("nickname", "can't be empty.") if nickname.blank?
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_on_create
|
71
|
+
puts 'MyModel.validate_on_create'
|
72
|
+
errors.add("save_count", "should be zero.") if !save_count.blank? && save_count > 0
|
73
|
+
end
|
39
74
|
|
40
|
-
|
75
|
+
def validate_on_update
|
76
|
+
puts 'MyModel.validate_on_update'
|
41
77
|
# puts 'save_count = ' + save_count.to_s
|
42
|
-
|
43
|
-
|
78
|
+
# errors.add("save_count", "should not be zero.") if save_count.blank? || save_count == 0
|
79
|
+
end
|
44
80
|
|
45
|
-
|
46
|
-
|
47
|
-
|
81
|
+
def atts
|
82
|
+
@@attributes
|
83
|
+
end
|
48
84
|
|
49
|
-
end
|
50
85
|
|
86
|
+
end
|
51
87
|
|
52
88
|
|
53
89
|
class SingleClobClass < SimpleRecord::Base
|
54
90
|
|
55
|
-
|
91
|
+
sr_config :single_clob=>true
|
56
92
|
|
57
|
-
|
93
|
+
has_strings :name
|
58
94
|
|
59
|
-
|
95
|
+
has_clobs :clob1, :clob2
|
60
96
|
end
|
data/test/my_sharded_model.rb
CHANGED
@@ -4,38 +4,43 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
|
|
4
4
|
|
5
5
|
class MyShardedModel < SimpleRecord::Base
|
6
6
|
|
7
|
-
|
7
|
+
shard :shards=>:my_shards, :map=>:my_mapping_function
|
8
8
|
|
9
|
-
|
9
|
+
has_strings :name
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def self.num_shards
|
12
|
+
4
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
shard_num
|
19
|
-
end
|
15
|
+
def self.my_shards
|
16
|
+
Array(0...self.num_shards)
|
17
|
+
end
|
20
18
|
|
19
|
+
def my_mapping_function
|
20
|
+
shard_num = SimpleRecord::Sharding::Hashing.sdbm_hash(self.id) % self.class.num_shards
|
21
|
+
puts "shard_num=" + shard_num.inspect
|
22
|
+
shard_num
|
23
|
+
end
|
21
24
|
|
25
|
+
def self.shard_for_find(id)
|
26
|
+
shard_num = SimpleRecord::Sharding::Hashing.sdbm_hash(id) % self.num_shards
|
27
|
+
end
|
22
28
|
|
23
29
|
end
|
24
30
|
|
25
31
|
|
26
32
|
class MyShardedByFieldModel < SimpleRecord::Base
|
27
33
|
|
28
|
-
|
34
|
+
shard :shards=>:my_shards, :map=>:my_mapping_function
|
29
35
|
|
30
|
-
|
36
|
+
has_strings :name, :state
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
def self.my_shards
|
39
|
+
['AL', 'CA', 'FL', 'NY']
|
40
|
+
end
|
35
41
|
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
def my_mapping_function
|
43
|
+
state
|
44
|
+
end
|
39
45
|
|
40
|
-
|
41
|
-
end
|
46
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
|
2
|
+
require_relative 'my_base_model'
|
3
|
+
require_relative 'my_sharded_model'
|
4
|
+
|
5
|
+
class MySimpleModel < SimpleRecord::Base
|
6
|
+
|
7
|
+
has_strings :name, :nickname, :s1, :s2
|
8
|
+
has_ints :age, :save_count
|
9
|
+
has_booleans :cool
|
10
|
+
has_dates :birthday, :date1, :date2, :date3
|
11
|
+
|
12
|
+
|
13
|
+
end
|
data/test/test_shards.rb
CHANGED
@@ -10,136 +10,139 @@ require_relative 'my_sharded_model'
|
|
10
10
|
#
|
11
11
|
class TestShards < TestBase
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def setup
|
14
|
+
super
|
15
|
+
delete_all MyShardedModel
|
16
|
+
delete_all MyShardedByFieldModel
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
super
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# We'll want to shard based on ID's, user decides how many shards and some mapping function will
|
25
|
+
# be used to select the shard.
|
26
|
+
def test_id_sharding
|
27
|
+
|
28
|
+
mm = MyShardedModel.new(:name=>"single")
|
29
|
+
mm.save
|
30
|
+
sleep 1
|
31
|
+
puts 'finding by id'
|
32
|
+
mm2 = MyShardedModel.find(mm.id)
|
33
|
+
p mm2
|
34
|
+
assert_equal mm.id, mm2.id
|
35
|
+
puts 'deleting'
|
36
|
+
mm2.delete
|
37
|
+
sleep 1
|
38
|
+
mm3 = MyShardedModel.find(mm.id)
|
39
|
+
assert_nil mm3
|
40
|
+
|
41
|
+
puts "saving 20 now"
|
42
|
+
saved = []
|
43
|
+
20.times do |i|
|
44
|
+
mm = MyShardedModel.new(:name=>"name #{i}")
|
45
|
+
mm.save
|
46
|
+
saved << mm
|
17
47
|
end
|
18
48
|
|
19
|
-
|
20
|
-
super
|
49
|
+
# todo: assert that we're actually sharding
|
21
50
|
|
51
|
+
puts "finding them all"
|
52
|
+
found = []
|
53
|
+
rs = MyShardedModel.find(:all)
|
54
|
+
rs.each do |m|
|
55
|
+
p m
|
56
|
+
found << m
|
22
57
|
end
|
58
|
+
saved.each do |so|
|
59
|
+
assert(found.find { |m1| m1.id == so.id })
|
60
|
+
end
|
61
|
+
|
62
|
+
puts "deleting all of them"
|
63
|
+
found.each do |fo|
|
64
|
+
fo.delete
|
65
|
+
end
|
66
|
+
|
67
|
+
puts "Now ensure that all are deleted"
|
68
|
+
rs = MyShardedModel.find(:all)
|
69
|
+
assert rs.size == 0
|
70
|
+
|
71
|
+
puts "Testing belongs_to sharding"
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_field_sharding
|
77
|
+
|
78
|
+
states = MyShardedByFieldModel.shards
|
79
|
+
puts "states=" + states.inspect
|
23
80
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
mm2.delete
|
37
|
-
sleep 1
|
38
|
-
mm3 = MyShardedModel.find(mm.id)
|
39
|
-
assert_nil mm3
|
40
|
-
|
41
|
-
puts "saving 20 now"
|
42
|
-
saved = []
|
43
|
-
20.times do |i|
|
44
|
-
mm = MyShardedModel.new(:name=>"name #{i}")
|
45
|
-
mm.save
|
46
|
-
saved << mm
|
47
|
-
end
|
48
|
-
|
49
|
-
# todo: assert that we're actually sharding
|
50
|
-
|
51
|
-
puts "finding them all"
|
52
|
-
found = []
|
53
|
-
rs = MyShardedModel.find(:all)
|
54
|
-
rs.each do |m|
|
55
|
-
p m
|
56
|
-
found << m
|
57
|
-
end
|
58
|
-
saved.each do |so|
|
59
|
-
assert(found.find { |m1| m1.id == so.id })
|
60
|
-
end
|
61
|
-
|
62
|
-
puts "deleting all of them"
|
63
|
-
found.each do |fo|
|
64
|
-
fo.delete
|
65
|
-
end
|
66
|
-
|
67
|
-
puts "Now ensure that all are deleted"
|
68
|
-
rs = MyShardedModel.find(:all)
|
69
|
-
assert rs.size == 0
|
81
|
+
mm = MyShardedByFieldModel.new(:name=>"single", :state=>"CA")
|
82
|
+
mm.save
|
83
|
+
sleep 1
|
84
|
+
puts 'finding by id'
|
85
|
+
mm2 = MyShardedByFieldModel.find(mm.id)
|
86
|
+
p mm2
|
87
|
+
assert_equal mm.id, mm2.id
|
88
|
+
puts 'deleting'
|
89
|
+
mm2.delete
|
90
|
+
sleep 1
|
91
|
+
mm3 = MyShardedByFieldModel.find(mm.id)
|
92
|
+
assert_nil mm3
|
70
93
|
|
94
|
+
puts "saving 20 now"
|
95
|
+
saved = []
|
96
|
+
20.times do |i|
|
97
|
+
mm = MyShardedByFieldModel.new(:name=>"name #{i}", :state=>states[i % states.size])
|
98
|
+
mm.save
|
99
|
+
p mm
|
100
|
+
saved << mm
|
71
101
|
end
|
72
102
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
mm = MyShardedByFieldModel.new(:name=>"name #{i}", :state=>states[i % states.size])
|
95
|
-
mm.save
|
96
|
-
p mm
|
97
|
-
saved << mm
|
98
|
-
end
|
99
|
-
|
100
|
-
sleep 1
|
101
|
-
# todo: assert that we're actually sharding
|
102
|
-
|
103
|
-
puts "finding them all"
|
104
|
-
found = []
|
105
|
-
rs = MyShardedByFieldModel.find(:all)
|
106
|
-
rs.each do |m|
|
107
|
-
p m
|
108
|
-
found << m
|
109
|
-
end
|
110
|
-
saved.each do |so|
|
111
|
-
assert(found.find { |m1| m1.id == so.id })
|
112
|
-
end
|
113
|
-
|
114
|
-
rs = MyShardedByFieldModel.find(:all)
|
115
|
-
rs.each do |m|
|
116
|
-
p m
|
117
|
-
found << m
|
118
|
-
end
|
119
|
-
saved.each do |so|
|
120
|
-
assert(found.find { |m1| m1.id == so.id })
|
121
|
-
end
|
122
|
-
|
123
|
-
# Try to find on a specific known shard
|
124
|
-
selects = SimpleRecord.stats.selects
|
125
|
-
cali_models = MyShardedByFieldModel.find(:all, :shard => "CA")
|
126
|
-
puts 'cali_models=' + cali_models.inspect
|
127
|
-
assert_equal(5, cali_models.size)
|
128
|
-
assert_equal(selects + 1, SimpleRecord.stats.selects)
|
129
|
-
|
130
|
-
puts "deleting all of them"
|
131
|
-
found.each do |fo|
|
132
|
-
fo.delete
|
133
|
-
end
|
134
|
-
sleep 1
|
135
|
-
|
136
|
-
puts "Now ensure that all are deleted"
|
137
|
-
rs = MyShardedByFieldModel.find(:all)
|
138
|
-
assert rs.size == 0
|
103
|
+
sleep 1
|
104
|
+
# todo: assert that we're actually sharding
|
105
|
+
|
106
|
+
puts "finding them all"
|
107
|
+
found = []
|
108
|
+
rs = MyShardedByFieldModel.find(:all)
|
109
|
+
rs.each do |m|
|
110
|
+
p m
|
111
|
+
found << m
|
112
|
+
end
|
113
|
+
saved.each do |so|
|
114
|
+
assert(found.find { |m1| m1.id == so.id })
|
115
|
+
end
|
116
|
+
|
117
|
+
rs = MyShardedByFieldModel.find(:all)
|
118
|
+
rs.each do |m|
|
119
|
+
p m
|
120
|
+
found << m
|
121
|
+
end
|
122
|
+
saved.each do |so|
|
123
|
+
assert(found.find { |m1| m1.id == so.id })
|
139
124
|
end
|
140
125
|
|
141
|
-
|
126
|
+
# Try to find on a specific known shard
|
127
|
+
selects = SimpleRecord.stats.selects
|
128
|
+
cali_models = MyShardedByFieldModel.find(:all, :shard => "CA")
|
129
|
+
puts 'cali_models=' + cali_models.inspect
|
130
|
+
assert_equal(5, cali_models.size)
|
131
|
+
assert_equal(selects + 1, SimpleRecord.stats.selects)
|
142
132
|
|
133
|
+
puts "deleting all of them"
|
134
|
+
found.each do |fo|
|
135
|
+
fo.delete
|
143
136
|
end
|
137
|
+
sleep 1
|
138
|
+
|
139
|
+
puts "Now ensure that all are deleted"
|
140
|
+
rs = MyShardedByFieldModel.find(:all)
|
141
|
+
assert rs.size == 0
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_time_sharding
|
145
|
+
|
146
|
+
end
|
144
147
|
|
145
148
|
end
|