dynashard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ class Shard < ActiveRecord::Base
2
+ def dsn
3
+ HashWithIndifferentAccess.new(self.attributes.reject{|k,v| v.nil? || ['name','id'].include?(k)})
4
+ end
5
+ end
6
+
7
+ # Owner class that doesn't shard its associations
8
+ class NonShardingOwner < ActiveRecord::Base
9
+ # Non-sharded associations
10
+ has_one :non_sharded_has_one
11
+ has_many :non_sharded_has_manys
12
+ has_many :non_sharded_joins
13
+ has_many :non_sharded_has_many_throughs, :through => :non_sharded_joins
14
+
15
+ # Sharded associations
16
+ has_one :sharded_has_one
17
+ has_many :sharded_has_manys
18
+ has_many :sharded_joins
19
+ has_many :sharded_has_many_throughs, :through => :sharded_joins
20
+ end
21
+
22
+ # Owner class for sharded associations
23
+ class ShardingOwner < ActiveRecord::Base
24
+ shard :associated, :using => :shard_dsn
25
+
26
+ belongs_to :shard
27
+ def shard_dsn
28
+ @dsn ||= shard.dsn
29
+ end
30
+
31
+ # Non-sharded associations
32
+ has_one :non_sharded_has_one
33
+ has_many :non_sharded_has_manys
34
+ has_many :non_sharded_joins
35
+ has_many :non_sharded_has_many_throughs, :through => :non_sharded_joins
36
+
37
+ # Sharded associations
38
+ has_one :sharded_has_one
39
+ has_many :sharded_has_manys
40
+ has_many :sharded_joins
41
+ has_many :sharded_has_many_throughs, :through => :sharded_joins
42
+ end
43
+
44
+ # Non-sharded has_one association class
45
+ class NonShardedHasOne < ActiveRecord::Base
46
+ belongs_to :sharding_owner
47
+
48
+ validates :name, :uniqueness => true
49
+ end
50
+
51
+ # Non-sharded has_many association class
52
+ class NonShardedHasMany < ActiveRecord::Base
53
+ belongs_to :sharding_owner
54
+ belongs_to :non_sharding_owner
55
+ end
56
+
57
+ # Join table for has_many :through
58
+ class NonShardedJoin < ActiveRecord::Base
59
+ belongs_to :sharding_owner
60
+ belongs_to :non_sharded_has_many_through
61
+ end
62
+
63
+ # Non-sharded has_many association class
64
+ class NonShardedHasManyThrough < ActiveRecord::Base
65
+ has_many :non_sharded_joins
66
+ end
67
+
68
+ # Sharded has_one association class
69
+ class ShardedHasOne < ActiveRecord::Base
70
+ shard :by => :owner
71
+
72
+ validates :name, :uniqueness => true
73
+
74
+ belongs_to :sharding_owner
75
+ belongs_to :non_sharding_owner
76
+ end
77
+
78
+ # Sharded has_many association class
79
+ class ShardedHasMany < ActiveRecord::Base
80
+ shard :by => :owner
81
+
82
+ belongs_to :sharding_owner
83
+ belongs_to :non_sharding_owner
84
+ end
85
+
86
+ # Join table for has_many :through
87
+ class ShardedJoin < ActiveRecord::Base
88
+ shard :by => :owner
89
+
90
+ belongs_to :sharding_owner
91
+ belongs_to :sharded_has_many_through
92
+ end
93
+
94
+ # Sharded has_many :through association class
95
+ class ShardedHasManyThrough < ActiveRecord::Base
96
+ shard :by => :owner
97
+
98
+ has_many :sharded_joins
99
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Dynashard::ValidationExtensions' do
4
+ before(:each) do
5
+ @owner = Factory(:sharding_owner)
6
+ end
7
+
8
+ describe '#find_finder_class_for' do
9
+ before(:each) do
10
+ @shard_klass = Dynashard.class_for(@owner.shard_dsn)
11
+ @sharded_model_subclass = Dynashard.sharded_model_class(@shard_klass, ShardedHasOne)
12
+ end
13
+
14
+ context 'when sharding' do
15
+ before(:each) do
16
+ @validator = ShardedHasOne.validators.detect{|v| v.is_a?(ActiveRecord::Validations::UniquenessValidator)}
17
+ end
18
+
19
+ context 'with a generated association owner class' do
20
+ it 'returns the generated class' do
21
+ new_record = @owner.build_sharded_has_one
22
+ @validator.send(:find_finder_class_for, new_record).should == @sharded_model_subclass
23
+ end
24
+ end
25
+
26
+ context 'with a model class' do
27
+ it 'returns the generated shard subclass' do
28
+ Dynashard.with_context(:owner => @owner.shard_dsn) do
29
+ new_record = ShardedHasOne.new
30
+ @validator.send(:find_finder_class_for, new_record).should == @sharded_model_subclass
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'when not sharding' do
37
+ before(:each) do
38
+ @validator = NonShardedHasOne.validators.detect{|v| v.is_a?(ActiveRecord::Validations::UniquenessValidator)}
39
+ end
40
+
41
+ context 'with a non-sharding association owner class' do
42
+ it 'returns the model class' do
43
+ non_sharding_owner = Factory(:non_sharding_owner)
44
+ new_record = non_sharding_owner.build_non_sharded_has_one
45
+ @validator.send(:find_finder_class_for, new_record).should == NonShardedHasOne
46
+ end
47
+ end
48
+
49
+ context 'with a non-sharding model class' do
50
+ it 'returns the model class' do
51
+ new_record = NonShardedHasOne.new
52
+ @validator.send(:find_finder_class_for, new_record).should == NonShardedHasOne
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'when validating uniqueness' do
59
+ context 'with an association proxy target' do
60
+ context 'with a conflicting record on the shard' do
61
+ it 'returns invalid' do
62
+ conflicting_record = Dynashard.with_context(:owner => @owner.shard_dsn){Factory(:sharded_has_one)}
63
+ new_record = @owner.build_sharded_has_one(:name => conflicting_record.name)
64
+ new_record.should_not be_valid
65
+ end
66
+ end
67
+
68
+ context 'with a conflicting record on a different shard' do
69
+ it 'returns valid' do
70
+ other_shard = Shard.find(:all).detect{|shard| shard != @owner.shard}
71
+ non_conflicting_record = Dynashard.with_context(:owner => other_shard.dsn){Factory(:sharded_has_one)}
72
+ new_record = @owner.build_sharded_has_one(:name => non_conflicting_record.name)
73
+ new_record.should be_valid
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'with a model class' do
79
+ context 'with a conflicting record on the shard' do
80
+ it 'returns invalid' do
81
+ conflicting_record = Dynashard.with_context(:owner => @owner.shard_dsn){Factory(:sharded_has_one)}
82
+ new_record = ShardedHasOne.new(:name => conflicting_record.name)
83
+ Dynashard.with_context(:owner => @owner.shard_dsn) do
84
+ new_record.should_not be_valid
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'with a conflicting record on a different shard' do
90
+ it 'returns valid' do
91
+ other_shard = Shard.find(:all).detect{|shard| shard != @owner.shard}
92
+ non_conflicting_record = Dynashard.with_context(:owner => other_shard.dsn){Factory(:sharded_has_one)}
93
+ new_record = ShardedHasOne.new(:name => non_conflicting_record.name)
94
+ Dynashard.with_context(:owner => @owner.shard_dsn) do
95
+ new_record.should be_valid
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynashard
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Nick Hengeveld
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-31 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: activerecord
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 3
33
+ - 0
34
+ version: "3.0"
35
+ requirement: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ type: :development
38
+ prerelease: false
39
+ name: shoulda
40
+ version_requirements: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ requirement: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ type: :development
52
+ prerelease: false
53
+ name: bundler
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 23
60
+ segments:
61
+ - 1
62
+ - 0
63
+ - 0
64
+ version: 1.0.0
65
+ requirement: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ type: :development
68
+ prerelease: false
69
+ name: jeweler
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 7
76
+ segments:
77
+ - 1
78
+ - 5
79
+ - 2
80
+ version: 1.5.2
81
+ requirement: *id004
82
+ - !ruby/object:Gem::Dependency
83
+ type: :development
84
+ prerelease: false
85
+ name: rcov
86
+ version_requirements: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ requirement: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ type: :runtime
98
+ prerelease: false
99
+ name: activerecord
100
+ version_requirements: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 7
106
+ segments:
107
+ - 3
108
+ - 0
109
+ version: "3.0"
110
+ requirement: *id006
111
+ description: Dynashard allows you to shard your ActiveRecord models. Models can be configured to shard based on context that can be defined dynamically.
112
+ email: nickh@verticalresponse.com
113
+ executables: []
114
+
115
+ extensions: []
116
+
117
+ extra_rdoc_files:
118
+ - LICENSE.txt
119
+ - README.md
120
+ files:
121
+ - .document
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - VERSION
128
+ - lib/dynashard.rb
129
+ - lib/dynashard/arel_sql_engine.rb
130
+ - lib/dynashard/associations.rb
131
+ - lib/dynashard/connection_handler.rb
132
+ - lib/dynashard/model.rb
133
+ - lib/dynashard/validations.rb
134
+ - spec/arel_sql_engine_spec.rb
135
+ - spec/associations_spec.rb
136
+ - spec/connection_handler_spec.rb
137
+ - spec/dynashard_spec.rb
138
+ - spec/model_spec.rb
139
+ - spec/spec_helper.rb
140
+ - spec/support/factories.rb
141
+ - spec/support/models.rb
142
+ - spec/validation_spec.rb
143
+ - spec/db/schema.rb
144
+ has_rdoc: true
145
+ homepage: http://github.com/nickh/dynashard
146
+ licenses:
147
+ - MIT
148
+ post_install_message:
149
+ rdoc_options: []
150
+
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: 3
159
+ segments:
160
+ - 0
161
+ version: "0"
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ hash: 3
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ requirements: []
172
+
173
+ rubyforge_project:
174
+ rubygems_version: 1.3.7
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: Dynamic sharding for ActiveRecord
178
+ test_files:
179
+ - spec/arel_sql_engine_spec.rb
180
+ - spec/associations_spec.rb
181
+ - spec/connection_handler_spec.rb
182
+ - spec/db/schema.rb
183
+ - spec/dynashard_spec.rb
184
+ - spec/model_spec.rb
185
+ - spec/spec_helper.rb
186
+ - spec/support/factories.rb
187
+ - spec/support/models.rb
188
+ - spec/validation_spec.rb