switchman 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +30 -0
- data/app/models/switchman/shard.rb +502 -0
- data/db/migrate/20130328212039_create_switchman_shards.rb +9 -0
- data/db/migrate/20130328224244_create_default_shard.rb +9 -0
- data/lib/switchman.rb +9 -0
- data/lib/switchman/active_record/abstract_adapter.rb +11 -0
- data/lib/switchman/active_record/association.rb +108 -0
- data/lib/switchman/active_record/attribute_methods.rb +104 -0
- data/lib/switchman/active_record/base.rb +95 -0
- data/lib/switchman/active_record/calculations.rb +63 -0
- data/lib/switchman/active_record/connection_handler.rb +147 -0
- data/lib/switchman/active_record/connection_pool.rb +117 -0
- data/lib/switchman/active_record/finder_methods.rb +25 -0
- data/lib/switchman/active_record/log_subscriber.rb +43 -0
- data/lib/switchman/active_record/postgresql_adapter.rb +13 -0
- data/lib/switchman/active_record/query_cache.rb +12 -0
- data/lib/switchman/active_record/query_methods.rb +184 -0
- data/lib/switchman/active_record/relation.rb +69 -0
- data/lib/switchman/cache_extensions.rb +12 -0
- data/lib/switchman/connection_pool_proxy.rb +62 -0
- data/lib/switchman/database_server.rb +197 -0
- data/lib/switchman/default_shard.rb +28 -0
- data/lib/switchman/engine.rb +91 -0
- data/lib/switchman/r_spec_helper.rb +124 -0
- data/lib/switchman/shackles.rb +34 -0
- data/lib/switchman/test_helper.rb +65 -0
- data/lib/switchman/version.rb +3 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/models/appendage.rb +24 -0
- data/spec/dummy/app/models/digit.rb +9 -0
- data/spec/dummy/app/models/feature.rb +5 -0
- data/spec/dummy/app/models/mirror_user.rb +5 -0
- data/spec/dummy/app/models/user.rb +23 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/database.yml.example +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/db/migrate/20130403132607_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20130411202442_create_appendages.rb +10 -0
- data/spec/dummy/db/migrate/20130411202551_create_mirror_users.rb +9 -0
- data/spec/dummy/db/migrate/20131022202028_create_digits.rb +10 -0
- data/spec/dummy/db/migrate/20131206172923_create_features.rb +12 -0
- data/spec/dummy/db/schema.rb +57 -0
- data/spec/dummy/log/development.log +504 -0
- data/spec/dummy/log/test.log +29907 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/tmp/cache/2E2/830/shard%2F2 +0 -0
- data/spec/dummy/tmp/cache/2E3/840/shard%2F3 +0 -0
- data/spec/dummy/tmp/cache/313/970/shard%2F30 +0 -0
- data/spec/dummy/tmp/cache/314/980/shard%2F31 +0 -0
- data/spec/dummy/tmp/cache/316/980/shard%2F15 +1 -0
- data/spec/dummy/tmp/cache/316/9D0/shard%2F60 +0 -0
- data/spec/dummy/tmp/cache/317/990/shard%2F16 +0 -0
- data/spec/dummy/tmp/cache/317/9C0/shard%2F43 +1 -0
- data/spec/dummy/tmp/cache/317/9E0/shard%2F61 +0 -0
- data/spec/dummy/tmp/cache/318/9A0/shard%2F17 +0 -0
- data/spec/dummy/tmp/cache/318/9D0/shard%2F44 +0 -0
- data/spec/dummy/tmp/cache/318/9F0/shard%2F62 +1 -0
- data/spec/dummy/tmp/cache/319/9E0/shard%2F45 +0 -0
- data/spec/dummy/tmp/cache/319/9F0/shard%2F54 +1 -0
- data/spec/dummy/tmp/cache/319/A10/shard%2F72 +1 -0
- data/spec/dummy/tmp/cache/319/A30/shard%2F90 +0 -0
- data/spec/dummy/tmp/cache/31B/9E0/shard%2F29 +1 -0
- data/spec/dummy/tmp/cache/321/AA0/shard%2F89 +0 -0
- data/spec/dummy/tmp/cache/322/AC0/shard%2F99 +1 -0
- data/spec/dummy/tmp/cache/344/D70/shard%2F103 +1 -0
- data/spec/dummy/tmp/cache/345/D80/shard%2F104 +0 -0
- data/spec/dummy/tmp/cache/345/DB0/shard%2F131 +1 -0
- data/spec/dummy/tmp/cache/345/DC0/shard%2F140 +0 -0
- data/spec/dummy/tmp/cache/346/D90/shard%2F105 +0 -0
- data/spec/dummy/tmp/cache/346/DB0/shard%2F123 +0 -0
- data/spec/dummy/tmp/cache/346/DD0/shard%2F222 +1 -0
- data/spec/dummy/tmp/cache/346/DE0/shard%2F150 +0 -0
- data/spec/dummy/tmp/cache/346/DF0/shard%2F240 +1 -0
- data/spec/dummy/tmp/cache/347/DA0/shard%2F106 +1 -0
- data/spec/dummy/tmp/cache/347/DC0/shard%2F124 +0 -0
- data/spec/dummy/tmp/cache/347/DC0/shard%2F205 +1 -0
- data/spec/dummy/tmp/cache/347/E10/shard%2F250 +1 -0
- data/spec/dummy/tmp/cache/348/DF0/shard%2F143 +1 -0
- data/spec/dummy/tmp/cache/348/DF0/shard%2F224 +1 -0
- data/spec/dummy/tmp/cache/348/E10/shard%2F161 +1 -0
- data/spec/dummy/tmp/cache/349/DD0/shard%2F117 +1 -0
- data/spec/dummy/tmp/cache/349/E40/shard%2F180 +1 -0
- data/spec/dummy/tmp/cache/34A/DF0/shard%2F127 +1 -0
- data/spec/dummy/tmp/cache/34A/DF0/shard%2F208 +1 -0
- data/spec/dummy/tmp/cache/34A/E10/shard%2F145 +1 -0
- data/spec/dummy/tmp/cache/34A/E60/shard%2F190 +1 -0
- data/spec/dummy/tmp/cache/34B/E30/shard%2F155 +1 -0
- data/spec/dummy/tmp/cache/34D/E30/shard%2F139 +0 -0
- data/spec/dummy/tmp/cache/34E/E50/shard%2F149 +0 -0
- data/spec/dummy/tmp/cache/353/EF0/shard%2F199 +1 -0
- data/spec/dummy/tmp/cache/3A4/E90/shard%2F10003 +1 -0
- data/spec/dummy/tmp/cache/3A5/ED0/shard%2F10031 +1 -0
- data/spec/dummy/tmp/cache/3A9/EF0/shard%2F10017 +1 -0
- data/spec/lib/active_record/association_spec.rb +305 -0
- data/spec/lib/active_record/attribute_methods_spec.rb +108 -0
- data/spec/lib/active_record/base_spec.rb +66 -0
- data/spec/lib/active_record/calculations_spec.rb +119 -0
- data/spec/lib/active_record/connection_handler_spec.rb +45 -0
- data/spec/lib/active_record/connection_pool_spec.rb +23 -0
- data/spec/lib/active_record/finder_methods_spec.rb +29 -0
- data/spec/lib/active_record/query_cache_spec.rb +20 -0
- data/spec/lib/active_record/query_methods_spec.rb +130 -0
- data/spec/lib/active_record/relation_spec.rb +38 -0
- data/spec/lib/cache_extensions_spec.rb +27 -0
- data/spec/lib/connection_pool_proxy_spec.rb +13 -0
- data/spec/lib/database_server_spec.rb +154 -0
- data/spec/lib/shackles_spec.rb +147 -0
- data/spec/models/shard_spec.rb +382 -0
- data/spec/spec_helper.rb +32 -0
- metadata +344 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1387233834.229409:@value":nil
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1387233783.55399:@value":nil
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347234.081155:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347205.332012:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346079.7480378:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1387233860.152838:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346810.801615:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347125.1334531:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347176.218136:@value":nil
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376345790.522966:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346962.726431:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346876.272081:@value":nil
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346876.201909:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347007.3382888:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346962.848526:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346920.458379:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346079.693532:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347153.642796:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376345698.2460349:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346920.485046:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376345721.1751559:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347205.233504:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376346810.651356:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376347007.318975:@value":nil
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1376345708.931933:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1384546201.9292722:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1387233783.433878:@value":nil
|
@@ -0,0 +1 @@
|
|
1
|
+
o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1384546433.2994628:@value":nil
|
@@ -0,0 +1,305 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Switchman
|
4
|
+
module ActiveRecord
|
5
|
+
describe Association do
|
6
|
+
include RSpecHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@shard1.activate do
|
10
|
+
@user1 = User.create!
|
11
|
+
end
|
12
|
+
@shard2.activate do
|
13
|
+
@user2 = User.create!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should associate built objects with parent shard" do
|
18
|
+
a1 = @user1.appendages.build
|
19
|
+
a1.shard.should == @shard1
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should associate created objects with parent shard" do
|
23
|
+
a1 = @user1.appendages.create!
|
24
|
+
a1.shard.should == @shard1
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should set shard value to parent for association scope" do
|
28
|
+
scope = @user1.appendages.scoped
|
29
|
+
scope.shard_value.should == @user1
|
30
|
+
scope.shard_source_value.should == :association
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should find by id through association" do
|
34
|
+
a1 = @user1.appendages.create!
|
35
|
+
|
36
|
+
@user1.appendages.find(a1.id).should == a1
|
37
|
+
lambda { @user2.appendages.find(a1.id) }.should raise_exception(::ActiveRecord::RecordNotFound)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "transaction" do
|
41
|
+
it "should activate the owner's shard and start the transaction on that shard" do
|
42
|
+
@user1.appendages.transaction(:requires_new => true) do
|
43
|
+
Shard.current.should == @shard1
|
44
|
+
User.connection.open_transactions.should == 2
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should get the record size" do
|
50
|
+
a1 = @user1.appendages.create!
|
51
|
+
a2 = @user1.appendages.build
|
52
|
+
@user1.appendages.size.should == 2
|
53
|
+
@user1.reload
|
54
|
+
@user1.appendages.size.should == 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should reverse the association" do
|
58
|
+
a1 = @user1.appendages.create!
|
59
|
+
a1.reload
|
60
|
+
a1.user.shard.should == @shard1
|
61
|
+
a1.user.should == @user1
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should work with has_many through associations" do
|
65
|
+
a1 = @user1.appendages.create!
|
66
|
+
d1 = a1.digits.create!
|
67
|
+
d1.shard.should == @shard1
|
68
|
+
|
69
|
+
@user1.digits.scoped.shard_value.should == @user1
|
70
|
+
@user1.digits.find(d1.id).should == d1
|
71
|
+
end
|
72
|
+
|
73
|
+
it "shard should be changeable, and change conditions when it is changed" do
|
74
|
+
a1 = @user1.appendages.create!
|
75
|
+
relation = @user1.appendages.where(:id => a1).shard(@shard1)
|
76
|
+
relation.shard_value.should == @shard1
|
77
|
+
relation.shard_source_value.should == :explicit
|
78
|
+
relation.where_values.detect{|v| v.left.name == "id"}.right.should == a1.local_id
|
79
|
+
|
80
|
+
relation = @user1.appendages.where(:id => a1).shard(@shard2)
|
81
|
+
relation.shard_value.should == @shard2
|
82
|
+
relation.shard_source_value.should == :explicit
|
83
|
+
relation.where_values.detect{|v| v.left.name == "id"}.right.should == a1.global_id
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should transpose predicates correctly" do
|
87
|
+
a1 = @user1.appendages.create!
|
88
|
+
a2 = @user2.appendages.create!
|
89
|
+
|
90
|
+
relation = @user1.appendages.where(:id => a2)
|
91
|
+
relation.shard_value.should == @user1
|
92
|
+
relation.where_values.detect{|v| v.left.name == "id"}.right.should == a2.global_id
|
93
|
+
|
94
|
+
relation = @user1.appendages.where(:id => [a1, a2])
|
95
|
+
relation.shard_value.should == @user1
|
96
|
+
relation.where_values.detect{|v| v.left.name == "id"}.right.should == [a1.local_id, a2.global_id]
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "multishard associations" do
|
100
|
+
it "should group has_many associations over associated_shards" do
|
101
|
+
@shard1.activate{ Appendage.create!(:user_id => @user1, :value => 1) }
|
102
|
+
@shard2.activate{ Appendage.create!(:user => @user1, :value => 2) }
|
103
|
+
|
104
|
+
@user1.appendages.to_a.map(&:value).should == [1]
|
105
|
+
|
106
|
+
@user1.reload
|
107
|
+
@user1.associated_shards = [@shard1, @shard2]
|
108
|
+
@user1.appendages.to_a.map(&:value).sort.should == [1, 2]
|
109
|
+
end
|
110
|
+
|
111
|
+
it "follow shards for has_many :through" do
|
112
|
+
@shard1.activate{ a1 = Appendage.create!(:user_id => @user1); a1.digits.create!(:value => 1) }
|
113
|
+
@shard2.activate{ a2 = Appendage.create!(:user_id => @user1); a2.digits.create!(:value => 2) }
|
114
|
+
|
115
|
+
@user1.digits.to_a.map(&:value).should == [1]
|
116
|
+
|
117
|
+
@user1.reload
|
118
|
+
@user1.associated_shards = [@shard1, @shard2]
|
119
|
+
@user1.digits.to_a.map(&:value).sort.should == [1, 2]
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should include the shard in scopes created by associations" do
|
123
|
+
@user1.associated_shards = [@shard1, @shard2]
|
124
|
+
|
125
|
+
@shard1.activate{ Appendage.create!(:user_id => @user1, :value => 1) }
|
126
|
+
@shard2.activate{ Appendage.create!(:user => @user1) }
|
127
|
+
|
128
|
+
@user1.appendages.has_no_value.to_a.count.should == 1
|
129
|
+
|
130
|
+
@user1.reload
|
131
|
+
@shard2.activate {@user1.appendages.has_no_value.to_a.count.should == 1}
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should include the shard in scopes created by has_many :through associations" do
|
135
|
+
@user1.associated_shards = [@shard1, @shard2]
|
136
|
+
|
137
|
+
@shard1.activate{ a1 = Appendage.create!(:user_id => @user1); a1.digits.create! }
|
138
|
+
@shard2.activate{ a2 = Appendage.create!(:user_id => @user1); a2.digits.create!(:value => 2) }
|
139
|
+
|
140
|
+
@user1.digits.has_no_value.count.should == 1
|
141
|
+
|
142
|
+
@user1.reload
|
143
|
+
@shard2.activate {@user1.digits.has_no_value.to_a.count.should == 1}
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should work with calculations in scopes created by associations" do
|
147
|
+
@user1.associated_shards = [@shard1, @shard2]
|
148
|
+
|
149
|
+
@shard1.activate{ Appendage.create!(:user_id => @user1, :value => 1) }
|
150
|
+
@shard2.activate{ Appendage.create!(:user => @user1); @user1.appendages.create!(:value => 2) }
|
151
|
+
|
152
|
+
@user1.reload
|
153
|
+
@user1.appendages.has_value.sum(:value).should == 3
|
154
|
+
|
155
|
+
@user1.reload
|
156
|
+
@shard2.activate {@user1.appendages.has_value.sum(:value).should == 3}
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should work with calculations in scopes created by has_many :through associations" do
|
160
|
+
@user1.associated_shards = [@shard1, @shard2]
|
161
|
+
@shard1.activate{ a1 = Appendage.create!(:user_id => @user1); a1.digits.create!; a1.digits.create!(:value => 1) }
|
162
|
+
@shard2.activate{ a2 = Appendage.create!(:user_id => @user1); a2.digits.create!(:value => 2) }
|
163
|
+
|
164
|
+
@user1.digits.has_value.sum(:value).should == 3
|
165
|
+
@user1.reload
|
166
|
+
@shard2.activate {@user1.digits.has_value.sum(:value).should == 3}
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should be able to explicitly set the shard and still work with named scopes" do
|
170
|
+
@user1.associated_shards = [@shard1, @shard2]
|
171
|
+
|
172
|
+
@shard1.activate{ a1 = Appendage.create!(:user_id => @user1); a1.digits.create! }
|
173
|
+
@shard2.activate{ a2 = Appendage.create!(:user_id => @user1); a2.digits.create!(:value => 2) }
|
174
|
+
|
175
|
+
@user1.digits.shard(@shard1).has_no_value.to_a.count.should == 1
|
176
|
+
@user1.digits.shard(@shard2).has_no_value.to_a.count.should == 0
|
177
|
+
|
178
|
+
@user1.reload
|
179
|
+
|
180
|
+
@user1.digits.has_no_value.shard(@shard1).to_a.count.should == 1
|
181
|
+
@user1.digits.has_no_value.shard(@shard2).to_a.count.should == 0
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "preloading" do
|
185
|
+
it "should preload belongs_to associations across shards" do
|
186
|
+
a1 = Appendage.create!(:user => @user1)
|
187
|
+
a2 = Appendage.create!(:user => @user2)
|
188
|
+
user3 = User.create!
|
189
|
+
user3.appendages.create!
|
190
|
+
|
191
|
+
appendages = Appendage.all(:include => :user)
|
192
|
+
appendages2 = Appendage.includes(:user).all
|
193
|
+
@user1.delete
|
194
|
+
|
195
|
+
appendages.map(&:user).sort.should == [@user1, @user2, user3].sort
|
196
|
+
appendages2.map(&:user).sort.should == [@user1, @user2, user3].sort
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should preload belongs_to :through associations across shards" do
|
200
|
+
a1 = Appendage.create!(:user => @user1)
|
201
|
+
d1 = a1.digits.create!
|
202
|
+
|
203
|
+
a2 = @shard1.activate {Appendage.create!(:user => @user2) }
|
204
|
+
d2 = Digit.create!(:appendage => a2)
|
205
|
+
|
206
|
+
digits = Digit.includes(:user).all
|
207
|
+
@user1.delete
|
208
|
+
|
209
|
+
digits.map(&:user).sort.should == [@user1, @user2].sort
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should preload has_many associations across associated shards" do
|
213
|
+
a1 = @user1.appendages.create!
|
214
|
+
a2 = @shard2.activate { Appendage.create!(:user_id => @user1) } # a2 will be in @user1's associated shards
|
215
|
+
a3 = @shard1.activate { Appendage.create!(:user_id => @user2) } # a3 is not on @user2's associated shard
|
216
|
+
|
217
|
+
User.associated_shards_map = { @user1.global_id => [@shard1, @shard2] }
|
218
|
+
|
219
|
+
begin
|
220
|
+
users = User.where(:id => [@user1, @user2]).includes(:appendages).all
|
221
|
+
users.each {|u| u.appendages.loaded?.should be_true}
|
222
|
+
|
223
|
+
u1 = users.detect {|u| u.id == @user1.id}
|
224
|
+
u2 = users.detect {|u| u.id == @user2.id}
|
225
|
+
|
226
|
+
a1.delete
|
227
|
+
u1.appendages.sort.should == [a1, a2].sort
|
228
|
+
u2.appendages.should be_empty
|
229
|
+
ensure
|
230
|
+
User.associated_shards_map = nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should preload has_many :through associations across associated shards" do
|
235
|
+
a1 = @user1.appendages.create!
|
236
|
+
a2 = @shard2.activate { Appendage.create!(:user_id => @user1) }
|
237
|
+
a3 = @shard2.activate { Appendage.create!(:user_id => @user1) }
|
238
|
+
|
239
|
+
d1 = a1.digits.create!
|
240
|
+
d2 = a2.digits.create! # a2 will be in @user1's associated shards
|
241
|
+
d3 = @shard1.activate { Digit.create!(:appendage_id => a2) } # d3 will be in a2's associated shards
|
242
|
+
d4 = @shard1.activate { Digit.create!(:appendage_id => a3) } # d4 is not on a3's shard
|
243
|
+
|
244
|
+
a4 = @shard1.activate { Appendage.create!(:user_id => @user2) }
|
245
|
+
a5 = @user2.appendages.create!
|
246
|
+
a6 = @user2.appendages.create!
|
247
|
+
|
248
|
+
d5 = @shard2.activate { Digit.create!(:appendage_id => a4) } # d5 is on @user2's shard but a4 is not
|
249
|
+
d6 = @shard1.activate { Digit.create!(:appendage_id => a5) } # a5 is on @user2's shard but d6 is not
|
250
|
+
d7 = @shard1.activate { Digit.create!(:appendage_id => a6) } # d7 will be in a6's associated shards
|
251
|
+
|
252
|
+
User.associated_shards_map = { @user1.global_id => [@shard1, @shard2] }
|
253
|
+
Appendage.associated_shards_map = { a2.global_id => [@shard1, @shard2], a6.global_id => [@shard1] }
|
254
|
+
|
255
|
+
begin
|
256
|
+
users = User.where(:id => [@user1, @user2]).includes(:digits).all
|
257
|
+
users.each {|u| u.digits.loaded?.should be_true}
|
258
|
+
|
259
|
+
u1 = users.detect {|u| u.id == @user1.id}
|
260
|
+
u2 = users.detect {|u| u.id == @user2.id}
|
261
|
+
|
262
|
+
d1.delete
|
263
|
+
|
264
|
+
u1.digits.sort.should == [d1, d2, d3].sort
|
265
|
+
u2.digits.should == [d7]
|
266
|
+
ensure
|
267
|
+
User.associated_shards_map = nil
|
268
|
+
Appendage.associated_shards_map = nil
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "polymorphic associations" do
|
274
|
+
it "should work normally" do
|
275
|
+
appendage = Appendage.create!
|
276
|
+
feature = Feature.create!(:owner => appendage)
|
277
|
+
|
278
|
+
feature.reload
|
279
|
+
feature.owner.should == appendage
|
280
|
+
feature.owner_id.should == appendage.id
|
281
|
+
feature.owner_type.should == "Appendage"
|
282
|
+
|
283
|
+
feature.owner = @user1
|
284
|
+
feature.save!
|
285
|
+
|
286
|
+
feature.reload
|
287
|
+
feature.owner_id.should == @user1.global_id
|
288
|
+
feature.owner_type.should == "User"
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should work with multi-shard associations" do
|
292
|
+
@shard1.activate{ Feature.create!(:owner => @user1, :value => 1) }
|
293
|
+
@shard2.activate{ Feature.create!(:owner => @user1, :value => 2) }
|
294
|
+
|
295
|
+
@user1.features.to_a.map(&:value).should == [1]
|
296
|
+
|
297
|
+
@user1.reload
|
298
|
+
@user1.associated_shards = [@shard1, @shard2]
|
299
|
+
@user1.features.to_a.map(&:value).sort.should == [1, 2]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|