connection_manager 0.3.11 → 1.0.1
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/Gemfile +0 -1
- data/README.md +1 -1
- data/connection_manager.gemspec +4 -4
- data/lib/connection_manager.rb +2 -0
- data/lib/connection_manager/patches/cross_schema_patch.rb +5 -5
- data/lib/connection_manager/patches/query_methods_patch.rb +15 -0
- data/lib/connection_manager/patches/reflections_patch.rb +19 -0
- data/lib/connection_manager/using.rb +2 -1
- data/lib/connection_manager/version.rb +1 -1
- data/spec/lib/replication_spec.rb +47 -32
- data/spec/lib/shards_spec.rb +5 -5
- data/spec/lib/using_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- metadata +22 -8
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -24,7 +24,7 @@ ConnectionManager is available through [Rubygems](https://rubygems.org/gems/conn
|
|
24
24
|
|
25
25
|
$ gem install connection_manager
|
26
26
|
|
27
|
-
## Rails 3 setup (No Rails 2 at this time)
|
27
|
+
## Rails 3/4 setup (No Rails 2 at this time)
|
28
28
|
|
29
29
|
Add connection_manager to you gemfile:
|
30
30
|
|
data/connection_manager.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Joshua Mckinney"]
|
9
9
|
s.email = ["joshmckin@gmail.com"]
|
10
10
|
s.homepage = ""
|
11
|
-
s.summary = %q{Simplifies connecting to
|
12
|
-
s.description = %q{Simplifies connecting to
|
11
|
+
s.summary = %q{Simplifies connecting to Multiple and Replication databases with rails and active_record}
|
12
|
+
s.description = %q{Simplifies connecting to Multiple and Replication databases with rails and active_record}
|
13
13
|
|
14
14
|
s.rubyforge_project = "connection_manager"
|
15
15
|
|
@@ -17,12 +17,12 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
|
-
s.add_runtime_dependency 'activerecord', '
|
20
|
+
s.add_runtime_dependency 'activerecord', '>= 3.0', '<= 4.0'
|
21
21
|
s.add_development_dependency 'rspec'
|
22
22
|
s.add_development_dependency 'autotest'
|
23
23
|
s.add_development_dependency 'mocha'
|
24
24
|
s.add_development_dependency 'factory_girl'
|
25
|
-
s.add_development_dependency 'activesupport', '
|
25
|
+
s.add_development_dependency 'activesupport', '>= 3.0', '<= 4.0'
|
26
26
|
|
27
27
|
if(defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE)
|
28
28
|
s.add_development_dependency 'jruby-openssl'
|
data/lib/connection_manager.rb
CHANGED
@@ -10,6 +10,8 @@ module ConnectionManager
|
|
10
10
|
require 'connection_manager/shards'
|
11
11
|
require 'connection_manager/replication'
|
12
12
|
require 'connection_manager/patches/cross_schema_patch'
|
13
|
+
require 'connection_manager/patches/reflections_patch'
|
14
|
+
require 'connection_manager/patches/query_methods_patch'
|
13
15
|
require 'connection_manager/connection_manager_railtie' if defined?(Rails)
|
14
16
|
|
15
17
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include,(ConnectionManager::AbstractAdapterHelper))
|
@@ -5,12 +5,12 @@ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 2
|
|
5
5
|
module ActiveRecord
|
6
6
|
module ConnectionAdapters
|
7
7
|
class Mysql2Adapter < ((ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 2) ? AbstractMysqlAdapter : AbstractAdapter)
|
8
|
-
|
8
|
+
|
9
9
|
# Force all tables to be cached for the life connection
|
10
10
|
def cached_tables
|
11
11
|
@cached_tables ||= {}
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def tables(name = nil, database = nil, like =nil)
|
15
15
|
return cached_tables[database] if cached_tables[database] && like.nil?
|
16
16
|
cached_tables[database] ||= []
|
@@ -21,9 +21,9 @@ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 2
|
|
21
21
|
result = execute(sql, 'SCHEMA')
|
22
22
|
cached_tables[database] = (cached_tables[database] | result.collect { |field| field[0] }).compact
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
alias :new_tables :tables
|
26
|
-
|
26
|
+
|
27
27
|
def table_exists?(name)
|
28
28
|
return false unless name
|
29
29
|
name = name.to_s
|
@@ -37,4 +37,4 @@ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 2
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module QueryMethods
|
3
|
+
private
|
4
|
+
# For some reason on .include or a custom join
|
5
|
+
# Arel drops the table name prefix on slave classes
|
6
|
+
def build_select(arel, selects)
|
7
|
+
unless selects.empty?
|
8
|
+
@implicit_readonly = false
|
9
|
+
arel.project(*selects)
|
10
|
+
else
|
11
|
+
arel.project("#{quoted_table_name}.*")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR <= 0
|
2
|
+
# Sometimes for some reason the quoted_table_name instance methods
|
3
|
+
# drops the schema. If the quoted table name does not include a '.'
|
4
|
+
# want to retrieve the quoted_table_name from the class and reset
|
5
|
+
module ActiveRecord
|
6
|
+
# = Active Record Reflection
|
7
|
+
module Reflection # :nodoc:
|
8
|
+
class AssociationReflection < MacroReflection
|
9
|
+
def table_name
|
10
|
+
@table_name = klass.table_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def quoted_table_name
|
14
|
+
@quoted_table_name = klass.quoted_table_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -25,7 +25,8 @@ module ConnectionManager
|
|
25
25
|
|
26
26
|
# Modifies the dup class to use the connection class connection.
|
27
27
|
# We want to use the current class table name, but the connection
|
28
|
-
# class database as the prefix
|
28
|
+
# class database as the prefix, useful when shards but normally
|
29
|
+
# should be the same. We also want the superclass method to
|
29
30
|
# return the connection class as AR sometimes uses the the superclass
|
30
31
|
# connection
|
31
32
|
def build_dup_class(connection_class_name)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
describe ConnectionManager::Replication do
|
3
|
-
|
3
|
+
|
4
4
|
describe '#database_name' do
|
5
5
|
it "should return the name of the database the model is using" do
|
6
6
|
Fruit.current_database_name.should eql('cm_test')
|
@@ -12,45 +12,61 @@ describe ConnectionManager::Replication do
|
|
12
12
|
Fruit.connection.stubs(:replication_keys).returns([])
|
13
13
|
lambda { Fruit.replicated }.should raise_error
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
it "should not raise an exception if no connections are empty, but connection.replication_keys are not blank" do
|
17
|
-
Fruit.connection.stubs(:replication_keys).returns([:slave_1_cm_test])
|
17
|
+
Fruit.connection.stubs(:replication_keys).returns([:slave_1_cm_test])
|
18
18
|
lambda { Fruit.replicated }.should_not raise_error
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
context "the methods created from #replicated" do
|
22
22
|
it "should create a method with the name given for the :name option" do
|
23
23
|
Fruit.replicated(:name => 'foozle')
|
24
24
|
Fruit.respond_to?(:foozle).should be_true
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should create a method in ActiveRecord::QueryMethods with the name given for the :name option" do
|
28
28
|
f = FactoryGirl.create(:fruit)
|
29
29
|
Fruit.replicated(:name => 'fizzle')
|
30
30
|
ActiveRecord::QueryMethods.instance_methods.include?(:fizzle).should be_true
|
31
31
|
Fruit.where(:id => f.id).fizzle.first.should_not eql(Fruit.where(:id => f.id).first)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it "should return an ActiveRecord::Relation" do
|
35
35
|
Fruit.replicated(:name => 'slaves')
|
36
36
|
Fruit.slaves.should be_kind_of(ActiveRecord::Relation)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
it "should have a different connection" do
|
40
40
|
Fruit.replicated
|
41
41
|
Fruit.slaves.connection.config.should_not eql(Fruit.connection.config)
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
|
+
it "should work" do
|
45
|
+
Fruit.replicated
|
46
|
+
Fruit.slaves.joins(:region).joins("LEFT OUTER JOIN `fruit_baskets` ON `fruit_baskets`.`fruit_id` = `cm_test`.`fruits`.`id`").to_sql.should eql(Fruit.joins(:region).joins("LEFT OUTER JOIN `fruit_baskets` ON `fruit_baskets`.`fruit_id` = `cm_test`.`fruits`.`id`").to_sql)
|
47
|
+
end
|
48
|
+
|
44
49
|
it "should produce the same query string" do
|
45
50
|
Fruit.replicated
|
46
51
|
Fruit.slaves.joins(:region).to_sql.should eql(Fruit.joins(:region).to_sql)
|
47
52
|
Fruit.slaves.joins(:fruit_baskets).to_sql.should eql(Fruit.joins(:fruit_baskets).to_sql)
|
48
|
-
Fruit.slaves.joins(:region).joins("LEFT OUTER JOIN `fruit_baskets` ON `fruit_baskets`.`fruit_id` = `cm_test`.`fruits`.`id`").to_sql.should eql(Fruit.joins(:region).joins("LEFT OUTER JOIN `fruit_baskets` ON `fruit_baskets`.`fruit_id` = `cm_test`.`fruits`.`id`").to_sql)
|
49
53
|
Fruit.slaves.includes(:fruit_baskets).to_sql.should eql(Fruit.includes(:fruit_baskets).to_sql)
|
50
54
|
Fruit.slaves.includes(:region).to_sql.should eql(Fruit.includes(:region).to_sql)
|
51
55
|
end
|
56
|
+
|
57
|
+
context '#slaves' do
|
58
|
+
it "should have the same quoted_table_name" do
|
59
|
+
Fruit.replicated
|
60
|
+
|
61
|
+
Fruit.slaves.quoted_table_name.should eql(Fruit.quoted_table_name)
|
62
|
+
end
|
63
|
+
it "should have the same table_name_prefix"do
|
64
|
+
Fruit.replicated
|
65
|
+
Fruit.slaves.table_name_prefix.should eql(Fruit.table_name_prefix)
|
66
|
+
end
|
67
|
+
end
|
52
68
|
end
|
53
|
-
|
69
|
+
|
54
70
|
context "the objects return from a query" do
|
55
71
|
# The default connection is the original connection for the model
|
56
72
|
it "should have the connection as the replication" do
|
@@ -58,10 +74,10 @@ describe ConnectionManager::Replication do
|
|
58
74
|
FactoryGirl.create(:fruit)
|
59
75
|
Fruit.slaves.first.connection.config.should eql(Fruit.slaves.connection.config)
|
60
76
|
Fruit.slaves.first.should_not be_nil
|
61
|
-
end
|
77
|
+
end
|
62
78
|
end
|
63
79
|
end
|
64
|
-
|
80
|
+
|
65
81
|
describe'#replicated?' do
|
66
82
|
it "should be false if not replicated" do
|
67
83
|
Fruit.replicated?.should be_false
|
@@ -71,34 +87,34 @@ describe ConnectionManager::Replication do
|
|
71
87
|
Fruit.replicated?.should be_true
|
72
88
|
end
|
73
89
|
end
|
74
|
-
|
75
|
-
|
90
|
+
|
91
|
+
|
76
92
|
|
77
93
|
#ConnectionManager::Connections.build_connection_classes(:env => 'test')
|
78
94
|
class CmFooSlaveConnection < ActiveRecord::Base
|
79
95
|
establish_managed_connection(:slave_1_cm_test)
|
80
96
|
end
|
81
|
-
|
97
|
+
|
82
98
|
class CmUserConnection < ActiveRecord::Base
|
83
99
|
establish_managed_connection(:cm_user_test)
|
84
100
|
end
|
85
|
-
|
101
|
+
|
86
102
|
class SlaveCmUserConnection < ActiveRecord::Base
|
87
103
|
establish_managed_connection(:slave_1_cm_user_test)
|
88
104
|
end
|
89
|
-
|
105
|
+
|
90
106
|
class User < CmUserConnection
|
91
107
|
has_many :foos
|
92
108
|
has_many(:foo_slaves, :class_name => "Foo::Slaves")
|
93
109
|
replicated('SlaveCmUserConnection')
|
94
|
-
|
110
|
+
|
95
111
|
end
|
96
|
-
|
112
|
+
|
97
113
|
class Foo < ActiveRecord::Base
|
98
114
|
belongs_to :user
|
99
115
|
replicated("CmFooSlaveConnection")
|
100
116
|
end
|
101
|
-
|
117
|
+
|
102
118
|
context "eager loading (#includes)" do
|
103
119
|
before :each do
|
104
120
|
@user = User.new(:name => "Testing")
|
@@ -106,38 +122,37 @@ describe ConnectionManager::Replication do
|
|
106
122
|
@foo = Foo.new(:user_id => @user.id)
|
107
123
|
@foo.save
|
108
124
|
end
|
109
|
-
|
125
|
+
|
110
126
|
# We'd like this to happen magically some day. Possible in 3.2
|
111
127
|
it "should eager load with replication instances" #do
|
112
|
-
# user = User.slaves.includes(:foos).where(:id => @user.id).first
|
113
|
-
# user.foos.first.should_not be_kind_of(Foo)
|
114
|
-
# end
|
115
|
-
|
128
|
+
# user = User.slaves.includes(:foos).where(:id => @user.id).first
|
129
|
+
# user.foos.first.should_not be_kind_of(Foo)
|
130
|
+
# end
|
131
|
+
|
116
132
|
context "specifically defined replication association" do
|
117
133
|
it "should eager load with replication instances" do
|
118
134
|
user = User.slaves.includes(:foo_slaves).where(:id => @user.id).first
|
119
135
|
user.foo_slaves.first.should_not be_kind_of(Foo)
|
120
136
|
end
|
121
|
-
end
|
137
|
+
end
|
122
138
|
end
|
123
|
-
context "cross database joins" do
|
139
|
+
context "cross database joins" do
|
124
140
|
before :each do
|
125
141
|
@user = User.new(:name => "Testing")
|
126
142
|
@user.save
|
127
143
|
@foo = Foo.new(:user_id => @user.id)
|
128
144
|
@foo.save
|
129
145
|
end
|
130
|
-
|
146
|
+
|
131
147
|
it "should work" do
|
132
|
-
@user.foos.blank?.should be_false
|
148
|
+
@user.foos.blank?.should be_false
|
133
149
|
found = Foo.select('users.name AS user_name').joins(:user).where(:id => @foo.id).first
|
134
150
|
found.user_name.blank?.should be_false
|
135
151
|
end
|
136
|
-
|
152
|
+
|
137
153
|
it "should work with replication" do
|
138
154
|
found = Foo.slaves.select('foos.*, users.name AS user_name').joins(:user).where(:id => @foo.id).first
|
139
155
|
found.user.blank?.should be_false
|
140
156
|
end
|
141
|
-
end
|
157
|
+
end
|
142
158
|
end
|
143
|
-
|
data/spec/lib/shards_spec.rb
CHANGED
@@ -23,18 +23,18 @@ describe ConnectionManager::Shards do
|
|
23
23
|
|
24
24
|
it "should not matter how the where statement is formated" do
|
25
25
|
fruit = FactoryGirl.create(:fruit)
|
26
|
-
|
26
|
+
afruit = Fruit.shards do |shard|
|
27
27
|
shard.where(:id => fruit.id).first
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
|
+
bfruit = Fruit.shards do |shard|
|
30
31
|
shard.where(['id = ?', fruit.id]).first
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
cfruit = Fruit.shards do |shard|
|
34
35
|
shard.where('id = ?', fruit.id).first
|
35
36
|
end
|
36
|
-
|
37
|
-
(a == b && b == c).should be_true
|
37
|
+
(afruit == bfruit && bfruit == cfruit).should be_true
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/spec/lib/using_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe ConnectionManager::Using do
|
|
10
10
|
|
11
11
|
it "should add sub class to current class with the name of the connection" do
|
12
12
|
Fruit.send(:fetch_duplicate_class,"CmFooSlaveConnection")
|
13
|
-
lambda { "Fruit::CmFooSlaveConnectionDup".constantize}.should_not raise_error
|
13
|
+
lambda { "Fruit::CmFooSlaveConnectionDup".constantize}.should_not raise_error
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#using' do
|
data/spec/spec_helper.rb
CHANGED
@@ -20,11 +20,11 @@ RSpec.configure do |config|
|
|
20
20
|
config.mock_with :mocha
|
21
21
|
# Loads database.yml and establishes primary connection
|
22
22
|
# Create tables when tests are completed
|
23
|
-
config.before(:
|
23
|
+
config.before(:suite) {
|
24
24
|
require 'helpers/models_spec_helper.rb'
|
25
25
|
}
|
26
26
|
# Drops tables when tests are completed
|
27
|
-
config.after(:
|
27
|
+
config.after(:suite){
|
28
28
|
TestDB.clean
|
29
29
|
}
|
30
30
|
# Make sure every test is isolated.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: connection_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,30 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '3.0'
|
22
|
+
- - <=
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '4.0'
|
22
25
|
type: :runtime
|
23
26
|
prerelease: false
|
24
27
|
version_requirements: !ruby/object:Gem::Requirement
|
25
28
|
none: false
|
26
29
|
requirements:
|
27
|
-
- -
|
30
|
+
- - ! '>='
|
28
31
|
- !ruby/object:Gem::Version
|
29
32
|
version: '3.0'
|
33
|
+
- - <=
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '4.0'
|
30
36
|
- !ruby/object:Gem::Dependency
|
31
37
|
name: rspec
|
32
38
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,17 +102,23 @@ dependencies:
|
|
96
102
|
requirement: !ruby/object:Gem::Requirement
|
97
103
|
none: false
|
98
104
|
requirements:
|
99
|
-
- -
|
105
|
+
- - ! '>='
|
100
106
|
- !ruby/object:Gem::Version
|
101
107
|
version: '3.0'
|
108
|
+
- - <=
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4.0'
|
102
111
|
type: :development
|
103
112
|
prerelease: false
|
104
113
|
version_requirements: !ruby/object:Gem::Requirement
|
105
114
|
none: false
|
106
115
|
requirements:
|
107
|
-
- -
|
116
|
+
- - ! '>='
|
108
117
|
- !ruby/object:Gem::Version
|
109
118
|
version: '3.0'
|
119
|
+
- - <=
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '4.0'
|
110
122
|
- !ruby/object:Gem::Dependency
|
111
123
|
name: mysql2
|
112
124
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,7 +135,7 @@ dependencies:
|
|
123
135
|
- - ! '>='
|
124
136
|
- !ruby/object:Gem::Version
|
125
137
|
version: '0'
|
126
|
-
description: Simplifies connecting to
|
138
|
+
description: Simplifies connecting to Multiple and Replication databases with rails
|
127
139
|
and active_record
|
128
140
|
email:
|
129
141
|
- joshmckin@gmail.com
|
@@ -144,6 +156,8 @@ files:
|
|
144
156
|
- lib/connection_manager/helpers/abstract_adapter_helper.rb
|
145
157
|
- lib/connection_manager/helpers/connection_helpers.rb
|
146
158
|
- lib/connection_manager/patches/cross_schema_patch.rb
|
159
|
+
- lib/connection_manager/patches/query_methods_patch.rb
|
160
|
+
- lib/connection_manager/patches/reflections_patch.rb
|
147
161
|
- lib/connection_manager/replication.rb
|
148
162
|
- lib/connection_manager/shards.rb
|
149
163
|
- lib/connection_manager/using.rb
|
@@ -184,7 +198,7 @@ rubyforge_project: connection_manager
|
|
184
198
|
rubygems_version: 1.8.25
|
185
199
|
signing_key:
|
186
200
|
specification_version: 3
|
187
|
-
summary: Simplifies connecting to
|
201
|
+
summary: Simplifies connecting to Multiple and Replication databases with rails and
|
188
202
|
active_record
|
189
203
|
test_files:
|
190
204
|
- spec/factories.rb
|