connection_manager 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/CHANGE.md +12 -0
- data/connection_manager.gemspec +2 -2
- data/lib/connection_manager.rb +0 -3
- data/lib/connection_manager/helpers/abstract_adapter_helper.rb +66 -16
- data/lib/connection_manager/helpers/connection_helpers.rb +1 -1
- data/lib/connection_manager/patches/cross_schema_patch.rb +33 -9
- data/lib/connection_manager/using.rb +54 -41
- data/lib/connection_manager/version.rb +1 -1
- data/spec/helpers/database_spec_helper.rb +67 -52
- data/spec/jdbcmysql_database.yml +0 -5
- data/spec/lib/patches/cross_schema_path_spec.rb +24 -0
- data/spec/lib/replication_spec.rb +2 -3
- data/spec/lib/using_spec.rb +5 -31
- data/spec/mysql2_database.yml +0 -5
- metadata +12 -27
- data/lib/connection_manager/patches/query_methods_patch.rb +0 -15
- data/lib/connection_manager/patches/reflections_patch.rb +0 -19
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjczOGY2MmMzMzFiMDBiNDNjYzhiMTE5NGVkZWM2OGRmOGUxYzdiNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MTIwMjQ1ODQ3ZGMwYTY0YWI0ZDgwNDM4NGM1MTE0MGYxMzE5ZjQxZQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MjAxNjI1Y2JjOGU0YjMzMWQyMzI0NjMyYzVmMmEzYTFjNWU3ZjBlNjk5OWNm
|
10
|
+
MDEyMTRmZDQ5MmRmMmFjYmUzMWVkYzNiNzk1OTRiMzgwNTRjOGMxYmExYzY2
|
11
|
+
Yjk1ZTRjMjI0MjkwY2U5YzM3ODBjNTQ2MzY3ZmRhOGM5M2VkYTM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
N2ZlMDg5N2NmOTEwNzQxN2ZlYmZkNjQyMmFlZDNmMTI3MjZjOTIwZWNmNWIy
|
14
|
+
MjZmYTQxZjE4M2QxYzg5ZTJjODZlM2FkMDIwMjY2MTE2ZDI1YzNjZGZjZjRi
|
15
|
+
N2Y5ZjZhZmQyMWNmYmMxYWM2ZGNhZWExYjEyM2Y5ODk3YTFmYTk=
|
data/CHANGE.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
ConnectionManager Changelog
|
2
|
+
=====================
|
3
|
+
|
4
|
+
HEAD
|
5
|
+
=======
|
6
|
+
- None yet!
|
7
|
+
|
8
|
+
1.0.2
|
9
|
+
=======
|
10
|
+
- ActiveRecord 4.1 compatibility
|
11
|
+
- Refactor Using to make use of active record relations
|
12
|
+
- Better cross schema patching, make sure AR < 3.2 loads
|
data/connection_manager.gemspec
CHANGED
@@ -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', '>= 3.0', '<= 4.
|
20
|
+
s.add_runtime_dependency 'activerecord', '>= 3.0', '<= 4.1'
|
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', '>= 3.0', '<= 4.
|
25
|
+
s.add_development_dependency 'activesupport', '>= 3.0', '<= 4.1'
|
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,15 +10,12 @@ 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'
|
15
13
|
require 'connection_manager/connection_manager_railtie' if defined?(Rails)
|
16
14
|
|
17
15
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include,(ConnectionManager::AbstractAdapterHelper))
|
18
16
|
ActiveRecord::Base.extend(ConnectionManager::ConnectionHelpers)
|
19
17
|
ActiveRecord::Base.extend(ConnectionManager::ConnectionBuilder)
|
20
18
|
ActiveRecord::Base.send(:include,ConnectionManager::Using)
|
21
|
-
ActiveRecord::QueryMethods.send(:include,ConnectionManager::UsingQueryMethod)
|
22
19
|
ActiveRecord::Base.extend(ConnectionManager::Replication)
|
23
20
|
ActiveRecord::Base.extend(ConnectionManager::Shards)
|
24
21
|
|
@@ -3,44 +3,94 @@ module ConnectionManager
|
|
3
3
|
def config
|
4
4
|
@config
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
# Determines if connection supports cross database queries
|
8
8
|
def cross_database_support?
|
9
|
-
|
9
|
+
(@config[:cross_database_support] || @config[:adapter].match(/(mysql)|(postgres)|(sqlserver)/i))
|
10
10
|
end
|
11
11
|
alias :cross_schema_support? :cross_database_support?
|
12
|
-
|
12
|
+
|
13
13
|
def using_em_adapter?
|
14
14
|
(@config[:adapter].match(/^em\_/) && defined?(EM) && EM::reactor_running?)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def readonly?
|
18
18
|
(@config[:readonly] == true)
|
19
|
-
end
|
20
|
-
|
19
|
+
end
|
20
|
+
|
21
21
|
def replicated?
|
22
22
|
(!slave_keys.blank? || !master_keys.blank?)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def database_name
|
26
26
|
@config[:database]
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def replication_keys(type=:slaves)
|
30
30
|
return slave_keys if type == :slaves
|
31
31
|
master_keys
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def slave_keys
|
35
|
-
|
36
|
-
|
37
|
-
slave_keys
|
35
|
+
return @config[:slaves].collect{|r| r.to_sym} if @config[:slaves]
|
36
|
+
[]
|
38
37
|
end
|
39
|
-
|
38
|
+
|
40
39
|
def master_keys
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
return @config[:masters].collect{|r| r.to_sym} if @config[:masters]
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
|
44
|
+
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1
|
45
|
+
|
46
|
+
# Returns the schema for a give table. Returns nil of multiple matches are found
|
47
|
+
def fetch_table_schema(table_name)
|
48
|
+
sql = "SELECT table_schema FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '#{table_name}'"
|
49
|
+
found = nil
|
50
|
+
results = execute(sql, 'SCHEMA')
|
51
|
+
found = results.to_a
|
52
|
+
if (found.length == 1)
|
53
|
+
found = found[0][0]
|
54
|
+
end
|
55
|
+
found
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns table_schema.table_name for the given table. Returns nil if multiple matches are found
|
59
|
+
def fetch_full_table_name(table_name)
|
60
|
+
return table_name if (table_name.to_s.match(/(^$)|(\.)/))
|
61
|
+
sql = "SELECT CONCAT(table_schema,'.',table_name) FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '#{table_name}'"
|
62
|
+
found = nil
|
63
|
+
results = execute(sql, 'SCHEMA')
|
64
|
+
found = results.to_a
|
65
|
+
if (found.length == 1)
|
66
|
+
found = found[0][0]
|
67
|
+
else
|
68
|
+
found = table_name
|
69
|
+
end
|
70
|
+
found
|
71
|
+
end
|
72
|
+
else
|
73
|
+
|
74
|
+
# Returns the schema for a give table. Returns nil of multiple matches are found
|
75
|
+
def fetch_table_schema(table_name)
|
76
|
+
sql = "SELECT table_schema FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '#{table_name}'"
|
77
|
+
execute_and_free(sql, 'SCHEMA') do |result|
|
78
|
+
found = result.to_a
|
79
|
+
return nil unless (found.length == 1)
|
80
|
+
found[0][0]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns table_schema.table_name for the given table. Returns nil if multiple matches are found
|
85
|
+
def fetch_full_table_name(table_name)
|
86
|
+
return table_name if (table_name.to_s.match(/(^$)|(\.)/))
|
87
|
+
sql = "SELECT CONCAT(table_schema,'.',table_name) FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '#{table_name}'"
|
88
|
+
execute_and_free(sql, 'SCHEMA') do |result|
|
89
|
+
found = result.to_a
|
90
|
+
return table_name unless (found.length == 1)
|
91
|
+
found[0][0]
|
92
|
+
end
|
93
|
+
end
|
44
94
|
end
|
45
95
|
end
|
46
96
|
end
|
@@ -74,7 +74,7 @@ module ConnectionManager
|
|
74
74
|
def use_database(database_name=nil,opts={})
|
75
75
|
self.current_database_name = database_name if database_name
|
76
76
|
opts[:table_name_prefix] = "#{self.current_database_name}." if opts[:table_name_prefix].blank? && self.connection.cross_database_support?
|
77
|
-
unless self.abstract_class?
|
77
|
+
unless self.abstract_class? || self.name == "ActiveRecord::Base"
|
78
78
|
opts[:table_name] = self.table_name if opts[:table_name].blank?
|
79
79
|
opts[:table_name].gsub!(self.table_name_prefix,'') unless self.table_name_prefix.blank?
|
80
80
|
self.table_name = "#{opts[:table_name_prefix]}#{opts[:table_name]}"
|
@@ -1,10 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
class << self
|
4
|
+
unless ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1
|
5
|
+
# We want to make sure we get the full table name with schema
|
6
|
+
def arel_table # :nodoc:
|
7
|
+
@arel_table ||= Arel::Table.new(quoted_table_name.to_s.gsub('`',''), arel_engine)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
alias :base_compute_table_name :compute_table_name
|
13
|
+
# In a schema schema environment we want to set table name prefix
|
14
|
+
# to the schema_name + . if its not set already
|
15
|
+
def compute_table_name
|
16
|
+
result = base_compute_table_name
|
17
|
+
if result.match(/^[^.]*$/) && connection.cross_schema_support?
|
18
|
+
t_schema = connection.fetch_table_schema(undecorated_table_name(name))
|
19
|
+
self.table_name_prefix = "#{t_schema}." if t_schema
|
20
|
+
result = base_compute_table_name
|
21
|
+
end
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1
|
29
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
5
30
|
module ActiveRecord
|
6
31
|
module ConnectionAdapters
|
7
|
-
class Mysql2Adapter <
|
32
|
+
class Mysql2Adapter < AbstractAdapter
|
8
33
|
|
9
34
|
# Force all tables to be cached for the life connection
|
10
35
|
def cached_tables
|
@@ -16,14 +41,13 @@ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 2
|
|
16
41
|
cached_tables[database] ||= []
|
17
42
|
return [like] if like && cached_tables[database].include?(like)
|
18
43
|
sql = "SHOW TABLES "
|
19
|
-
sql << "IN #{
|
44
|
+
sql << "IN #{database} " if database
|
20
45
|
sql << "LIKE #{quote(like)}" if like
|
21
46
|
result = execute(sql, 'SCHEMA')
|
22
47
|
cached_tables[database] = (cached_tables[database] | result.collect { |field| field[0] }).compact
|
23
48
|
end
|
24
49
|
|
25
|
-
|
26
|
-
|
50
|
+
# We have to clean the name of '`' and fetch table name with schema
|
27
51
|
def table_exists?(name)
|
28
52
|
return false unless name
|
29
53
|
name = name.to_s
|
@@ -32,7 +56,7 @@ if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 2
|
|
32
56
|
table = schema
|
33
57
|
schema = nil
|
34
58
|
end
|
35
|
-
|
59
|
+
tables(nil, schema, table).include?(table)
|
36
60
|
end
|
37
61
|
end
|
38
62
|
end
|
@@ -1,79 +1,92 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
1
2
|
module ConnectionManager
|
2
3
|
module Using
|
3
4
|
module ClassMethods
|
4
|
-
|
5
|
-
def using(connection_class_name)
|
6
|
-
d = fetch_duplicate_class(connection_class_name)
|
7
|
-
r = ActiveRecord::Relation.new(d, d.arel_table)
|
8
|
-
r = r.readonly if d.connection.readonly?
|
9
|
-
r = r.from(d.quoted_table_name) unless (ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0)
|
10
|
-
r
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
5
|
+
|
14
6
|
# We use dup here because its just too tricky to make sure we override
|
15
|
-
# all the methods necessary when using a child class of the model. This
|
7
|
+
# all the methods necessary when using a child class of the model. This
|
16
8
|
# action is lazy and the created sub is named to a constant so we only
|
17
9
|
# have to do it once.
|
18
|
-
def fetch_duplicate_class(connection_class_name)
|
10
|
+
def fetch_duplicate_class(connection_class_name)
|
19
11
|
begin
|
20
12
|
return "#{self.name}::#{connection_class_name}Dup".constantize
|
21
13
|
rescue NameError
|
22
14
|
return build_dup_class(connection_class_name)
|
23
15
|
end
|
24
16
|
end
|
25
|
-
|
17
|
+
|
18
|
+
private
|
26
19
|
# Modifies the dup class to use the connection class connection.
|
27
20
|
# We want to use the current class table name, but the connection
|
28
|
-
# class database as the prefix, useful when shards but normally
|
29
|
-
# should be the same. We also want the superclass method to
|
21
|
+
# class database as the prefix, useful when shards but normally
|
22
|
+
# should be the same. We also want the superclass method to
|
30
23
|
# return the connection class as AR sometimes uses the the superclass
|
31
24
|
# connection
|
32
25
|
def build_dup_class(connection_class_name)
|
33
26
|
use_database(self.current_database_name) # make sure we are consistent from super to dup
|
34
27
|
con_class = connection_class_name.constantize
|
35
28
|
db_name = con_class.current_database_name
|
36
|
-
dup_klass = dup
|
29
|
+
dup_klass = dup
|
37
30
|
dup_klass.class_eval <<-STR
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
def superclass
|
50
|
-
connection_class
|
51
|
-
end
|
31
|
+
self.use_database('#{db_name}',{:table_name => '#{table_name}'})
|
32
|
+
class << self
|
33
|
+
def model_name
|
34
|
+
#{self.name}.model_name
|
35
|
+
end
|
36
|
+
def connection_class
|
37
|
+
#{connection_class_name}
|
38
|
+
end
|
39
|
+
def connection
|
40
|
+
connection_class.connection
|
52
41
|
end
|
42
|
+
def superclass
|
43
|
+
connection_class
|
44
|
+
end
|
45
|
+
end
|
53
46
|
STR
|
54
|
-
|
47
|
+
|
55
48
|
self.const_set("#{connection_class_name}Dup", dup_klass)
|
56
49
|
"#{self.name}::#{connection_class_name}Dup".constantize
|
57
50
|
end
|
58
51
|
end
|
59
|
-
|
52
|
+
|
60
53
|
# Instance method for casting to a duplication class
|
61
54
|
def using(connection_class)
|
62
55
|
becomes(self.class.using(connection_class).klass)
|
63
56
|
end
|
64
|
-
|
57
|
+
|
65
58
|
def self.included(host_class)
|
66
59
|
host_class.extend(ClassMethods)
|
67
60
|
end
|
68
61
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
62
|
+
end
|
63
|
+
|
64
|
+
module ActiveRecord
|
65
|
+
# = Active Record Relation
|
66
|
+
class Relation
|
67
|
+
if ActiveRecord::VERSION::MAJOR == 4
|
68
|
+
def using(connection_class_name)
|
69
|
+
d = @klass.fetch_duplicate_class(connection_class_name)
|
70
|
+
self.instance_variable_set(:@arel_table, d.arel_table)
|
71
|
+
self.instance_variable_set(:@klass, d)
|
72
|
+
self
|
73
|
+
end
|
74
|
+
else
|
75
|
+
def using(connection_class_name)
|
76
|
+
d = @klass.fetch_duplicate_class(connection_class_name)
|
77
|
+
rel = clone
|
78
|
+
rel.instance_variable_set(:@arel_table, d.arel_table)
|
79
|
+
rel.instance_variable_set(:@klass, d)
|
80
|
+
rel
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module ActiveRecord
|
87
|
+
class Base
|
88
|
+
class << self
|
89
|
+
delegate :using, :to => (ActiveRecord::VERSION::MAJOR == 4 ? :all : :scoped)
|
77
90
|
end
|
78
91
|
end
|
79
92
|
end
|
@@ -2,13 +2,13 @@ class TestDB
|
|
2
2
|
def self.yml(driver='sqlite')
|
3
3
|
YAML::load(File.open(File.join(File.dirname(__FILE__),'..',"#{driver}_database.yml")))
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
def self.connect(driver='sqlite',logging=false)
|
7
7
|
ActiveRecord::Base.configurations = yml(driver)
|
8
|
-
ActiveRecord::Base.establish_connection('test')
|
8
|
+
ActiveRecord::Base.establish_connection('test')
|
9
9
|
ActiveRecord::Base.logger = Logger.new(STDOUT) if logging
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def self.clean
|
13
13
|
[:foos,:fruits,:baskets,:fruit_baskets,:regions,:types].each do |t|
|
14
14
|
DBSpecManagement.connection.execute("DELETE FROM #{t.to_s}")
|
@@ -19,46 +19,63 @@ class TestDB
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
22
|
#Put all the test migrations here
|
24
|
-
class TestMigrations < ActiveRecord::Migration
|
23
|
+
class TestMigrations < ActiveRecord::Migration
|
25
24
|
# all the ups
|
26
|
-
def self.up(connection_name='test',
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
25
|
+
def self.up(connection_name='test', user_connection_name='cm_user_test')
|
26
|
+
ActiveRecord::Base.establish_connection(connection_name)
|
27
|
+
begin
|
28
|
+
create_table "#{ActiveRecord::Base.schema_name}.foos" do |t|
|
29
|
+
t.string :name
|
30
|
+
t.integer :user_id
|
31
|
+
end
|
32
|
+
rescue => e
|
33
|
+
puts "tables failed to create: #{e}"
|
34
|
+
end
|
35
|
+
begin
|
36
|
+
create_table "#{ActiveRecord::Base.schema_name}.fruits" do |t|
|
37
|
+
t.string :name
|
38
|
+
t.integer :region_id
|
39
|
+
t.timestamps
|
40
|
+
end
|
41
|
+
rescue => e
|
42
|
+
puts "tables failed to create: #{e}"
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
create_table "#{ActiveRecord::Base.schema_name}.baskets" do |t|
|
46
|
+
t.string :name
|
47
|
+
t.timestamps
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
puts "tables failed to create: #{e}"
|
51
|
+
end
|
52
|
+
begin
|
53
|
+
create_table "#{ActiveRecord::Base.schema_name}.fruit_baskets" do |t|
|
54
|
+
t.integer :fruit_id
|
55
|
+
t.integer :basket_id
|
56
|
+
t.timestamps
|
57
|
+
end
|
58
|
+
rescue => e
|
59
|
+
puts "tables failed to create: #{e}"
|
60
|
+
end
|
61
|
+
begin
|
62
|
+
create_table "#{ActiveRecord::Base.schema_name}.regions" do |t|
|
63
|
+
t.string :name
|
64
|
+
t.integer :type_id
|
65
|
+
t.timestamps
|
66
|
+
end
|
67
|
+
rescue => e
|
68
|
+
puts "tables failed to create: #{e}"
|
69
|
+
end
|
70
|
+
begin
|
71
|
+
create_table "#{ActiveRecord::Base.schema_name}.types" do |t|
|
72
|
+
t.string :name
|
73
|
+
t.timestamps
|
59
74
|
end
|
75
|
+
rescue => e
|
76
|
+
puts "tables failed to create: #{e}"
|
60
77
|
end
|
61
|
-
|
78
|
+
|
62
79
|
ActiveRecord::Base.establish_connection(user_connection_name)
|
63
80
|
begin
|
64
81
|
create_table :users do |t|
|
@@ -67,30 +84,28 @@ class TestMigrations < ActiveRecord::Migration
|
|
67
84
|
rescue => e
|
68
85
|
puts "tables failed to create: #{e}"
|
69
86
|
end
|
70
|
-
|
87
|
+
|
71
88
|
ActiveRecord::Base.establish_connection(connection_name)
|
72
89
|
end
|
73
|
-
|
90
|
+
|
74
91
|
# all the downs
|
75
|
-
def self.down(connection_name='test',
|
76
|
-
|
77
|
-
|
92
|
+
def self.down(connection_name='test',user_connection_name='cm_user_test')
|
93
|
+
ActiveRecord::Base.establish_connection(connection_name)
|
94
|
+
[:foos,:fruits,:baskets,:fruit_baskets,:regions,:types].each do |t|
|
78
95
|
begin
|
79
|
-
|
80
|
-
drop_table t
|
81
|
-
end
|
96
|
+
drop_table t
|
82
97
|
rescue => e
|
83
98
|
puts "tables were not dropped: #{e}"
|
84
99
|
end
|
85
100
|
end
|
86
|
-
ActiveRecord::Base.establish_connection(user_connection_name)
|
101
|
+
ActiveRecord::Base.establish_connection(user_connection_name)
|
87
102
|
begin
|
88
103
|
[:users].each do |t|
|
89
|
-
drop_table t
|
104
|
+
drop_table t
|
90
105
|
end
|
91
106
|
rescue => e
|
92
107
|
puts "tables were not dropped: #{e}"
|
93
108
|
end
|
94
|
-
ActiveRecord::Base.establish_connection(connection_name)
|
95
|
-
end
|
96
|
-
end
|
109
|
+
ActiveRecord::Base.establish_connection(connection_name)
|
110
|
+
end
|
111
|
+
end
|
data/spec/jdbcmysql_database.yml
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
3
|
+
describe '#fetch_full_table_name' do
|
4
|
+
it "should return a string consisting of the schema name, a '.' and the table_name" do
|
5
|
+
Fruit.connection.fetch_full_table_name('fruits').should eql('cm_test.fruits')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#table_exists?' do
|
10
|
+
it "should return true for unquoted full_names" do
|
11
|
+
Fruit.connection.table_exists?('cm_test.fruits').should be_true
|
12
|
+
end
|
13
|
+
it "should return true for table only names" do
|
14
|
+
Fruit.connection.table_exists?('fruits').should be_true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe ActiveRecord::Base do
|
19
|
+
describe '#arel_table' do
|
20
|
+
it "should use quote_table_name" do
|
21
|
+
Fruit.arel_table.name.should eql('cm_test.fruits')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -68,11 +68,10 @@ describe ConnectionManager::Replication do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
context "the objects return from a query" do
|
71
|
-
|
72
|
-
it "should have the connection as the replication" do
|
71
|
+
it "should not have the same connection as the master class" do
|
73
72
|
Fruit.replicated
|
74
73
|
FactoryGirl.create(:fruit)
|
75
|
-
Fruit.slaves.
|
74
|
+
Fruit.slaves.connection.config.should_not eql(Fruit.connection.config)
|
76
75
|
Fruit.slaves.first.should_not be_nil
|
77
76
|
end
|
78
77
|
end
|
data/spec/lib/using_spec.rb
CHANGED
@@ -2,9 +2,6 @@ require 'spec_helper'
|
|
2
2
|
class CmFooSlaveConnection < ActiveRecord::Base
|
3
3
|
establish_managed_connection(:slave_1_cm_test)
|
4
4
|
end
|
5
|
-
class CmMasterConnection < ActiveRecord::Base
|
6
|
-
establish_managed_connection(:master_2_cm_test)
|
7
|
-
end
|
8
5
|
|
9
6
|
describe ConnectionManager::Using do
|
10
7
|
|
@@ -21,10 +18,11 @@ describe ConnectionManager::Using do
|
|
21
18
|
Fruit.using("CmFooSlaveConnection").connection.config.should_not eql(Fruit.connection.config)
|
22
19
|
end
|
23
20
|
|
24
|
-
it "should create the exact same sql if called from model or from relation"
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
it "should create the exact same sql if called from model or from relation" do
|
22
|
+
class_sql = Fruit.using("CmFooSlaveConnection").where(:name => "malarky").to_sql
|
23
|
+
relation_sql = Fruit.where(:name => "malarky").using("CmFooSlaveConnection").to_sql
|
24
|
+
class_sql.should eql(relation_sql)
|
25
|
+
end
|
28
26
|
|
29
27
|
it "should have the same connection if called from model or from relation" do
|
30
28
|
Fruit.where(:name => "malarky").using("CmFooSlaveConnection").connection.config.should eql(
|
@@ -34,30 +32,6 @@ describe ConnectionManager::Using do
|
|
34
32
|
Fruit.where(:name => "malarky").using("CmFooSlaveConnection").connection.config.should_not eql(
|
35
33
|
Fruit.where(:name => "malarky").connection.config)
|
36
34
|
end
|
37
|
-
|
38
|
-
it "should work" do
|
39
|
-
FactoryGirl.create(:fruit)
|
40
|
-
Fruit.using("CmFooSlaveConnection").first
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should really use a different connection" do
|
44
|
-
f = Fruit.using("CmMasterConnection").new
|
45
|
-
f.name = FactoryGirl.generate(:rand_name)
|
46
|
-
f.save
|
47
|
-
Fruit.where(:name => "malarky").first.should be_nil
|
48
|
-
Fruit.using("CmFooSlaveConnection").where(:name => f.name).first.should be_nil
|
49
|
-
Fruit.using("CmMasterConnection").where(:name => f.name).first.should_not be_nil
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should save to schema/database set in connection class" do
|
53
|
-
Fruit.table_name_prefix = "cm_test."
|
54
|
-
f = Fruit.using("CmMasterConnection").new
|
55
|
-
f.name = FactoryGirl.generate(:rand_name)
|
56
|
-
f.save
|
57
|
-
Fruit.where(:name => f.name).first.should be_nil
|
58
|
-
Fruit.using("CmFooSlaveConnection").where(:name => f.name).first.should be_nil
|
59
|
-
Fruit.using("CmMasterConnection").where(:name => f.name).first.should_not be_nil
|
60
|
-
end
|
61
35
|
end
|
62
36
|
end
|
63
37
|
|
data/spec/mysql2_database.yml
CHANGED
metadata
CHANGED
@@ -1,42 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: connection_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.2
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Joshua Mckinney
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-04-24 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '3.0'
|
22
20
|
- - <=
|
23
21
|
- !ruby/object:Gem::Version
|
24
|
-
version: '4.
|
22
|
+
version: '4.1'
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
25
|
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
26
|
requirements:
|
30
27
|
- - ! '>='
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: '3.0'
|
33
30
|
- - <=
|
34
31
|
- !ruby/object:Gem::Version
|
35
|
-
version: '4.
|
32
|
+
version: '4.1'
|
36
33
|
- !ruby/object:Gem::Dependency
|
37
34
|
name: rspec
|
38
35
|
requirement: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
36
|
requirements:
|
41
37
|
- - ! '>='
|
42
38
|
- !ruby/object:Gem::Version
|
@@ -44,7 +40,6 @@ dependencies:
|
|
44
40
|
type: :development
|
45
41
|
prerelease: false
|
46
42
|
version_requirements: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
43
|
requirements:
|
49
44
|
- - ! '>='
|
50
45
|
- !ruby/object:Gem::Version
|
@@ -52,7 +47,6 @@ dependencies:
|
|
52
47
|
- !ruby/object:Gem::Dependency
|
53
48
|
name: autotest
|
54
49
|
requirement: !ruby/object:Gem::Requirement
|
55
|
-
none: false
|
56
50
|
requirements:
|
57
51
|
- - ! '>='
|
58
52
|
- !ruby/object:Gem::Version
|
@@ -60,7 +54,6 @@ dependencies:
|
|
60
54
|
type: :development
|
61
55
|
prerelease: false
|
62
56
|
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
57
|
requirements:
|
65
58
|
- - ! '>='
|
66
59
|
- !ruby/object:Gem::Version
|
@@ -68,7 +61,6 @@ dependencies:
|
|
68
61
|
- !ruby/object:Gem::Dependency
|
69
62
|
name: mocha
|
70
63
|
requirement: !ruby/object:Gem::Requirement
|
71
|
-
none: false
|
72
64
|
requirements:
|
73
65
|
- - ! '>='
|
74
66
|
- !ruby/object:Gem::Version
|
@@ -76,7 +68,6 @@ dependencies:
|
|
76
68
|
type: :development
|
77
69
|
prerelease: false
|
78
70
|
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
none: false
|
80
71
|
requirements:
|
81
72
|
- - ! '>='
|
82
73
|
- !ruby/object:Gem::Version
|
@@ -84,7 +75,6 @@ dependencies:
|
|
84
75
|
- !ruby/object:Gem::Dependency
|
85
76
|
name: factory_girl
|
86
77
|
requirement: !ruby/object:Gem::Requirement
|
87
|
-
none: false
|
88
78
|
requirements:
|
89
79
|
- - ! '>='
|
90
80
|
- !ruby/object:Gem::Version
|
@@ -92,7 +82,6 @@ dependencies:
|
|
92
82
|
type: :development
|
93
83
|
prerelease: false
|
94
84
|
version_requirements: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
85
|
requirements:
|
97
86
|
- - ! '>='
|
98
87
|
- !ruby/object:Gem::Version
|
@@ -100,29 +89,26 @@ dependencies:
|
|
100
89
|
- !ruby/object:Gem::Dependency
|
101
90
|
name: activesupport
|
102
91
|
requirement: !ruby/object:Gem::Requirement
|
103
|
-
none: false
|
104
92
|
requirements:
|
105
93
|
- - ! '>='
|
106
94
|
- !ruby/object:Gem::Version
|
107
95
|
version: '3.0'
|
108
96
|
- - <=
|
109
97
|
- !ruby/object:Gem::Version
|
110
|
-
version: '4.
|
98
|
+
version: '4.1'
|
111
99
|
type: :development
|
112
100
|
prerelease: false
|
113
101
|
version_requirements: !ruby/object:Gem::Requirement
|
114
|
-
none: false
|
115
102
|
requirements:
|
116
103
|
- - ! '>='
|
117
104
|
- !ruby/object:Gem::Version
|
118
105
|
version: '3.0'
|
119
106
|
- - <=
|
120
107
|
- !ruby/object:Gem::Version
|
121
|
-
version: '4.
|
108
|
+
version: '4.1'
|
122
109
|
- !ruby/object:Gem::Dependency
|
123
110
|
name: mysql2
|
124
111
|
requirement: !ruby/object:Gem::Requirement
|
125
|
-
none: false
|
126
112
|
requirements:
|
127
113
|
- - ! '>='
|
128
114
|
- !ruby/object:Gem::Version
|
@@ -130,7 +116,6 @@ dependencies:
|
|
130
116
|
type: :development
|
131
117
|
prerelease: false
|
132
118
|
version_requirements: !ruby/object:Gem::Requirement
|
133
|
-
none: false
|
134
119
|
requirements:
|
135
120
|
- - ! '>='
|
136
121
|
- !ruby/object:Gem::Version
|
@@ -145,6 +130,7 @@ extra_rdoc_files: []
|
|
145
130
|
files:
|
146
131
|
- .gitignore
|
147
132
|
- .rspec
|
133
|
+
- CHANGE.md
|
148
134
|
- Gemfile
|
149
135
|
- LICENSE.txt
|
150
136
|
- README.md
|
@@ -156,8 +142,6 @@ files:
|
|
156
142
|
- lib/connection_manager/helpers/abstract_adapter_helper.rb
|
157
143
|
- lib/connection_manager/helpers/connection_helpers.rb
|
158
144
|
- 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
|
161
145
|
- lib/connection_manager/replication.rb
|
162
146
|
- lib/connection_manager/shards.rb
|
163
147
|
- lib/connection_manager/using.rb
|
@@ -168,6 +152,7 @@ files:
|
|
168
152
|
- spec/jdbcmysql_database.yml
|
169
153
|
- spec/lib/connection_builder_spec.rb
|
170
154
|
- spec/lib/connection_helpers_spec.rb
|
155
|
+
- spec/lib/patches/cross_schema_path_spec.rb
|
171
156
|
- spec/lib/replication_spec.rb
|
172
157
|
- spec/lib/shards_spec.rb
|
173
158
|
- spec/lib/using_spec.rb
|
@@ -177,27 +162,26 @@ files:
|
|
177
162
|
- spec/sqlite_database.yml
|
178
163
|
homepage: ''
|
179
164
|
licenses: []
|
165
|
+
metadata: {}
|
180
166
|
post_install_message:
|
181
167
|
rdoc_options: []
|
182
168
|
require_paths:
|
183
169
|
- lib
|
184
170
|
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
171
|
requirements:
|
187
172
|
- - ! '>='
|
188
173
|
- !ruby/object:Gem::Version
|
189
174
|
version: '0'
|
190
175
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
-
none: false
|
192
176
|
requirements:
|
193
177
|
- - ! '>='
|
194
178
|
- !ruby/object:Gem::Version
|
195
179
|
version: '0'
|
196
180
|
requirements: []
|
197
181
|
rubyforge_project: connection_manager
|
198
|
-
rubygems_version:
|
182
|
+
rubygems_version: 2.2.2
|
199
183
|
signing_key:
|
200
|
-
specification_version:
|
184
|
+
specification_version: 4
|
201
185
|
summary: Simplifies connecting to Multiple and Replication databases with rails and
|
202
186
|
active_record
|
203
187
|
test_files:
|
@@ -207,6 +191,7 @@ test_files:
|
|
207
191
|
- spec/jdbcmysql_database.yml
|
208
192
|
- spec/lib/connection_builder_spec.rb
|
209
193
|
- spec/lib/connection_helpers_spec.rb
|
194
|
+
- spec/lib/patches/cross_schema_path_spec.rb
|
210
195
|
- spec/lib/replication_spec.rb
|
211
196
|
- spec/lib/shards_spec.rb
|
212
197
|
- spec/lib/using_spec.rb
|
@@ -1,15 +0,0 @@
|
|
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
|
@@ -1,19 +0,0 @@
|
|
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
|