connection_manager 1.0.1 → 1.0.2
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.
- 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
|