connection_manager 0.1.4 → 0.2.0
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.lock +2 -2
- data/README.md +1 -1
- data/lib/connection_manager/associations.rb +0 -1
- data/lib/connection_manager/connections.rb +25 -24
- data/lib/connection_manager/method_recorder.rb +57 -0
- data/lib/connection_manager/{replication_builder.rb → secondary_connection_builder.rb} +58 -29
- data/lib/connection_manager/version.rb +1 -1
- data/lib/connection_manager.rb +7 -2
- data/spec/database.yml +7 -1
- data/spec/integration/{replication_builder_spec.rb → secondary_connection_builder_spec.rb} +3 -4
- data/spec/lib/associations_spec.rb +2 -1
- data/spec/lib/connections_spec.rb +12 -13
- data/spec/lib/method_recorder_spec.rb +39 -0
- data/spec/lib/{replication_builder_spec.rb → secondary_connection_builder_spec.rb} +8 -8
- metadata +22 -19
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
connection_manager (0.
|
4
|
+
connection_manager (0.2.0)
|
5
5
|
activerecord (~> 3.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -39,7 +39,7 @@ GEM
|
|
39
39
|
rspec-expectations (2.7.0)
|
40
40
|
diff-lcs (~> 1.1.2)
|
41
41
|
rspec-mocks (2.7.0)
|
42
|
-
sqlite3 (1.3.
|
42
|
+
sqlite3 (1.3.5)
|
43
43
|
tzinfo (0.3.31)
|
44
44
|
|
45
45
|
PLATFORMS
|
data/README.md
CHANGED
@@ -119,7 +119,7 @@ available slave connections each time it is called using a different connection
|
|
119
119
|
User.slave.where(['created_at BETWEEN ? and ?',Time.now - 5.days, Time.now]).all => returns results from slave_2_user_data_development
|
120
120
|
|
121
121
|
## TODO's
|
122
|
-
* sharding
|
122
|
+
* sharding - IN 2.0 AS BETA
|
123
123
|
|
124
124
|
## Other activerecord Connection gems
|
125
125
|
* [Octopus](https://github.com/tchandy/octopus)
|
@@ -3,7 +3,7 @@ module ConnectionManager
|
|
3
3
|
class << self
|
4
4
|
@connection_keys
|
5
5
|
@all
|
6
|
-
@
|
6
|
+
@secondary_connections
|
7
7
|
@env
|
8
8
|
|
9
9
|
def env
|
@@ -16,7 +16,7 @@ module ConnectionManager
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Get the current environment if defined
|
19
|
-
# Check for Rails, check for RACK_ENV,
|
19
|
+
# Check for Rails, check for RACK_ENV, default to 'development'
|
20
20
|
def fetch_env
|
21
21
|
return Rails.env if defined?(Rails)
|
22
22
|
return RACK_ENV if defined?(RACK_ENV)
|
@@ -36,23 +36,23 @@ module ConnectionManager
|
|
36
36
|
end
|
37
37
|
|
38
38
|
# Holds connections
|
39
|
-
def
|
40
|
-
@
|
39
|
+
def secondary_connections
|
40
|
+
@secondary_connections ||= {}
|
41
41
|
end
|
42
42
|
|
43
43
|
# Returns the database value given a connection key from the database.yml
|
44
44
|
def database_name_from_yml(name_from_yml)
|
45
|
-
ActiveRecord::Base.configurations[name_from_yml]['database']
|
45
|
+
clean_db_name(ActiveRecord::Base.configurations[name_from_yml]['database'])
|
46
46
|
end
|
47
|
-
|
48
|
-
def clean_sqlite_db_name(name)
|
47
|
+
|
48
|
+
def clean_sqlite_db_name(name,remove_env=true)
|
49
49
|
new_name = "#{name}".gsub(/(\.sqlite3$)/,'')
|
50
50
|
new_name = new_name.split("/").last
|
51
|
-
new_name.gsub!(Regexp.new("(\_#{env}$)"),'')
|
51
|
+
new_name.gsub!(Regexp.new("(\_#{env}$)"),'') if remove_env
|
52
52
|
new_name
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
55
|
+
def clean_db_name(name)
|
56
56
|
new_name = "#{name}".gsub(Regexp.new("#{env}$"),'')
|
57
57
|
if new_name.blank?
|
58
58
|
new_name = "#{database_name_from_yml(name)}"
|
@@ -64,27 +64,27 @@ module ConnectionManager
|
|
64
64
|
# Given an connection key name from the database.yml, returns the string
|
65
65
|
# equivelent of the class name for that entry.
|
66
66
|
def connection_class_name(name_from_yml)
|
67
|
-
new_class_name =
|
67
|
+
new_class_name = clean_db_name(name_from_yml)
|
68
68
|
new_class_name = new_class_name.gsub(/\_/,' ').titleize.gsub(/ /,'')
|
69
69
|
new_class_name << "Connection"
|
70
70
|
new_class_name
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
rep_name =
|
73
|
+
def secondary_key(name_from_yml)
|
74
|
+
rep_name = clean_db_name(name_from_yml)
|
75
75
|
rep_name.gsub!(/(\_)+(\d+)/,'')
|
76
76
|
rep_name.to_sym
|
77
77
|
end
|
78
78
|
|
79
|
-
def
|
80
|
-
key =
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
def add_secondary_connection(name_from_yml,new_connection)
|
80
|
+
key = secondary_key(name_from_yml)
|
81
|
+
secondary_connections[key] ||= []
|
82
|
+
secondary_connections[key] << new_connection
|
83
|
+
secondary_connections
|
84
84
|
end
|
85
85
|
|
86
|
-
def
|
87
|
-
|
86
|
+
def available_secondary_connections(rep_collection_key)
|
87
|
+
secondary_connections[(rep_collection_key.gsub(Regexp.new("(\_#{env}$)"),'')).to_sym]
|
88
88
|
end
|
89
89
|
|
90
90
|
# Sets class instance attributes, then builds connection classes, while populating
|
@@ -95,7 +95,7 @@ module ConnectionManager
|
|
95
95
|
end
|
96
96
|
connection_keys.each do |connection|
|
97
97
|
new_connection = connection_class_name(connection)
|
98
|
-
|
98
|
+
add_secondary_connection(connection,new_connection)
|
99
99
|
build_connection_class(new_connection,connection)
|
100
100
|
end
|
101
101
|
all
|
@@ -104,12 +104,13 @@ module ConnectionManager
|
|
104
104
|
# Addes a conneciton subclass to Connections using the supplied
|
105
105
|
# class name and connection key from database.yml
|
106
106
|
def build_connection_class(class_name,connection_key)
|
107
|
-
|
108
|
-
class #{class_name} < ActiveRecord::Base
|
107
|
+
klass = Class.new(ActiveRecord::Base) do
|
109
108
|
self.abstract_class = true
|
110
|
-
establish_connection("#{connection_key}")
|
111
109
|
end
|
112
|
-
|
110
|
+
new_connection_class = Object.const_set(class_name, klass)
|
111
|
+
new_connection_class.establish_connection(connection_key)
|
112
|
+
|
113
|
+
(const_set class_name, new_connection_class)
|
113
114
|
all << class_name
|
114
115
|
end
|
115
116
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
module ConnectionManager
|
3
|
+
class MethodRecorder
|
4
|
+
attr_accessor :classes_to_call
|
5
|
+
|
6
|
+
def initialize(classes_to_call=[])
|
7
|
+
self.classes_to_call = classes_to_call
|
8
|
+
end
|
9
|
+
|
10
|
+
# A place to store our methods and thier variables
|
11
|
+
def recordings
|
12
|
+
@recordings ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute_recordings
|
16
|
+
results = []
|
17
|
+
classes_to_call.each do |class_to_call|
|
18
|
+
called = nil
|
19
|
+
recordings.each do |name,args|
|
20
|
+
args = args[0] if [Array, Hash].include?args[0].class
|
21
|
+
if called.nil?
|
22
|
+
if args.blank?
|
23
|
+
called = class_to_call.send(name.to_sym)
|
24
|
+
else
|
25
|
+
called = class_to_call.send(name.to_sym, args)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
if args.blank?
|
29
|
+
called = called.send(name.to_sym)
|
30
|
+
else
|
31
|
+
called = called.send(name.to_sym, args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
if called.is_a?(Array)
|
36
|
+
results = (results | called)
|
37
|
+
else
|
38
|
+
results << called
|
39
|
+
end
|
40
|
+
end
|
41
|
+
results
|
42
|
+
end
|
43
|
+
|
44
|
+
# Create recorder classes for methods that might be called on a ActiveRecord
|
45
|
+
# model in the process of building a query
|
46
|
+
(ActiveRecord::FinderMethods.instance_methods | ActiveRecord::QueryMethods.instance_methods).each do |method|
|
47
|
+
define_method(method) do |*args|
|
48
|
+
recordings[method] = args
|
49
|
+
self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def execute
|
54
|
+
execute_recordings
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module ConnectionManager
|
2
|
-
module
|
2
|
+
module SecondaryConnectionBuilder
|
3
3
|
|
4
4
|
def database_name
|
5
5
|
"#{connection.instance_variable_get(:@config)[:database].to_s}"
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def secondary_association_options(method,association,class_name,options={})
|
9
9
|
new_options = {}.merge(options)
|
10
10
|
if new_options[:class_name].blank?
|
11
11
|
new_options[:class_name] = "#{association.to_s.singularize.classify}::#{class_name}"
|
@@ -19,14 +19,14 @@ module ConnectionManager
|
|
19
19
|
new_options
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def build_secondary_associations(class_name)
|
23
23
|
str = ""
|
24
24
|
defined_associations.each do |method,defs|
|
25
25
|
unless defs.blank?
|
26
26
|
defs.each do |association,options|
|
27
27
|
options = {} if options.blank?
|
28
28
|
unless options[:no_readonly] || options[:class_name].to_s.match("::#{class_name}")
|
29
|
-
str << "#{method.to_s} :#{association}, #{
|
29
|
+
str << "#{method.to_s} :#{association}, #{secondary_association_options(method,association,class_name,options)};"
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -34,28 +34,36 @@ module ConnectionManager
|
|
34
34
|
str
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
37
|
+
def secondary_connection_classes(options)
|
38
38
|
if options[:using] && options[:using].is_a?(Array)
|
39
39
|
connection_classes = options[:using].collect{|c| Connections.connection_class_name(c)}
|
40
40
|
else
|
41
41
|
rep_name = "#{options[:name].to_s}_#{Connections.clean_sqlite_db_name(database_name)}"
|
42
|
-
connection_classes = Connections.
|
42
|
+
connection_classes = Connections.available_secondary_connections(rep_name)
|
43
43
|
end
|
44
44
|
connection_classes
|
45
45
|
end
|
46
|
-
|
47
46
|
|
47
|
+
def replicated(*settings)
|
48
|
+
options = {:name => "slave", :readonly => true, :replication => true}.merge(settings.extract_options!)
|
49
|
+
build_secondary_connections(options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def sharded(*settings)
|
53
|
+
options = {:name => "shard", :readonly => false, :shards => true}.merge(settings.extract_options!)
|
54
|
+
build_secondary_connections(options)
|
55
|
+
end
|
56
|
+
|
48
57
|
# Adds subclass with the class name of the type provided in the options, which
|
49
58
|
# defaults to 'slave' if blank, that uses the connection from a connection class.
|
50
59
|
# If :database option is blank?, replicated will assume the database.yml has
|
51
60
|
# slave connections defined as: slave_database_name_test or slave_1_database_name_test,
|
52
|
-
# where slave_1 is the
|
61
|
+
# where slave_1 is the secondary instance, 'database_name' is the actual
|
53
62
|
# name of the database and '_test' is the Rails environment
|
54
|
-
def
|
55
|
-
|
56
|
-
connection_classes = replication_connection_classes(options)
|
63
|
+
def build_secondary_connections(options={})
|
64
|
+
connection_classes = secondary_connection_classes(options)
|
57
65
|
if connection_classes.blank?
|
58
|
-
raise ArgumentError, " a
|
66
|
+
raise ArgumentError, " a secondary connection was not found. Check your database.yml."
|
59
67
|
else
|
60
68
|
connection_methods = []
|
61
69
|
connection_classes.each do |c|
|
@@ -64,32 +72,34 @@ module ConnectionManager
|
|
64
72
|
method_name = method_name.insert(method_name.index(/\d/),"_")
|
65
73
|
class_name = method_name.classify
|
66
74
|
connection_methods << method_name.to_sym
|
67
|
-
|
68
|
-
|
75
|
+
build_secondary_class(class_name,c,options)
|
76
|
+
build_single_secondary_method(method_name,class_name)
|
77
|
+
set_table_name_for_joins
|
69
78
|
end
|
70
79
|
end
|
71
|
-
|
72
|
-
|
80
|
+
|
81
|
+
build_slaves_method(connection_methods) if options[:replication]
|
82
|
+
build_shards_method(connection_methods) if options[:shards]
|
73
83
|
end
|
74
84
|
|
75
85
|
# Creats a subclass that inherets from the model. The default model_name
|
76
86
|
# class method is overriden to return the super's name, which ensures rails
|
77
|
-
# helpers like link_to called on a
|
78
|
-
# master database. If options include readonly,
|
87
|
+
# helpers like link_to called on a secondary stance generate a url for the
|
88
|
+
# master database. If options include readonly, build_secondary_class also
|
79
89
|
# overrides the rails "readonly?" method to ensure saves are prevented.
|
80
|
-
#
|
90
|
+
# secondary class can be called directly for operaitons.
|
81
91
|
# Usage:
|
82
92
|
# User::Slave1.where(:id => 1).first => returns results from slave_1 database
|
83
|
-
# User::Slave2.where(:id => 2).first => returns results from
|
84
|
-
|
93
|
+
# User::Slave2.where(:id => 2).first => returns results from slave_2 database
|
94
|
+
# User::Shard1.where(:id => 2).first => returns results from slave_1 database
|
95
|
+
def build_secondary_class(class_name,connection_name,options)
|
85
96
|
class_eval <<-STR, __FILE__, __LINE__
|
86
97
|
class #{class_name} < self
|
87
|
-
#{
|
98
|
+
#{build_secondary_associations(class_name)}
|
88
99
|
class << self
|
89
100
|
def connection
|
90
101
|
Connections::#{connection_name}.connection
|
91
102
|
end
|
92
|
-
|
93
103
|
def model_name
|
94
104
|
ActiveModel::Name.new(#{name})
|
95
105
|
end
|
@@ -99,11 +109,15 @@ module ConnectionManager
|
|
99
109
|
STR
|
100
110
|
end
|
101
111
|
|
102
|
-
|
112
|
+
def set_table_name_for_joins
|
113
|
+
self.table_name_prefix = "#{database_name}." unless database_name.match(/\.sqlite3$/)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Adds as class method to call a specific secondary conneciton.
|
103
117
|
# Usage:
|
104
118
|
# User.slave_1.where(:id => 2).first => returns results from slave_1 database
|
105
119
|
# User.slave_2.where(:id => 2).first => returns results from slave_2 database
|
106
|
-
def
|
120
|
+
def build_single_secondary_method(method_name,class_name)
|
107
121
|
class_eval <<-STR, __FILE__, __LINE__
|
108
122
|
class << self
|
109
123
|
def #{method_name}
|
@@ -117,21 +131,36 @@ module ConnectionManager
|
|
117
131
|
# on each call.
|
118
132
|
# Usage:
|
119
133
|
# User.slave.where(:id => 2).first => can return results from slave_1 or slave_2
|
120
|
-
def
|
134
|
+
def build_slaves_method(connection_methods)
|
121
135
|
class_eval <<-STR, __FILE__, __LINE__
|
122
136
|
@connection_methods = #{connection_methods}
|
123
137
|
class << self
|
124
|
-
def
|
138
|
+
def slaves
|
125
139
|
current = @connection_methods.shift
|
126
140
|
@connection_methods << current
|
127
141
|
send(current)
|
128
142
|
end
|
143
|
+
alias :slave :slaves
|
129
144
|
def connection_methods
|
130
145
|
@connection_methods
|
131
146
|
end
|
132
147
|
end
|
133
148
|
STR
|
134
149
|
end
|
150
|
+
|
151
|
+
# add a class method that shifts through available connections methods
|
152
|
+
# on each call.
|
153
|
+
# Usage:
|
154
|
+
# User.shards.where(:id => 2).first => can return results from slave_1 or slave_2
|
155
|
+
def build_shards_method(connection_methods)
|
156
|
+
class_eval <<-STR, __FILE__, __LINE__
|
157
|
+
@shard_connection_methods = #{connection_methods}
|
158
|
+
class << self
|
159
|
+
def shards
|
160
|
+
ConnectionManager::MethodRecorder.new(@shard_connection_methods)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
STR
|
164
|
+
end
|
135
165
|
end
|
136
|
-
end
|
137
|
-
ActiveRecord::Base.extend(ConnectionManager::ReplicationBuilder)
|
166
|
+
end
|
data/lib/connection_manager.rb
CHANGED
@@ -4,7 +4,12 @@ module ConnectionManager
|
|
4
4
|
require 'active_record'
|
5
5
|
require 'connection_manager/connections'
|
6
6
|
require 'connection_manager/associations'
|
7
|
-
require 'connection_manager/
|
8
|
-
require 'connection_manager/
|
7
|
+
require 'connection_manager/secondary_connection_builder'
|
8
|
+
require 'connection_manager/method_recorder'
|
9
|
+
require 'connection_manager/connection_manager_railtie.rb' if defined?(Rails)
|
10
|
+
|
11
|
+
ActiveRecord::Base.extend(ConnectionManager::Associations)
|
12
|
+
ActiveRecord::Base.extend(ConnectionManager::SecondaryConnectionBuilder)
|
13
|
+
|
9
14
|
end
|
10
15
|
|
data/spec/database.yml
CHANGED
@@ -2,11 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
# Tests for associations build form replication.
|
4
4
|
|
5
|
-
describe ConnectionManager::
|
5
|
+
describe ConnectionManager::SecondaryConnectionBuilder do
|
6
6
|
before(:all) do
|
7
7
|
# Make sure connections recreated in other tests do not presist to current
|
8
8
|
ConnectionManager::Connections.all.clear
|
9
|
-
ConnectionManager::Connections.
|
9
|
+
ConnectionManager::Connections.secondary_connections.clear
|
10
10
|
|
11
11
|
#Initialize
|
12
12
|
ConnectionManager::Connections.initialize(:env => 'test')
|
@@ -44,8 +44,7 @@ describe ConnectionManager::ReplicationBuilder do
|
|
44
44
|
context "slave" do
|
45
45
|
context('belongs_to') do
|
46
46
|
it "should return the same belongs to object as master" do
|
47
|
-
fruit = Factory.create(:fruit)
|
48
|
-
|
47
|
+
fruit = Factory.create(:fruit)
|
49
48
|
slave_fruit = Fruit.slave.where(:id => fruit.id).first
|
50
49
|
slave_fruit.region.id.should eql(fruit.region.id)
|
51
50
|
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
|
3
2
|
class Foo < ActiveRecord::Base
|
4
3
|
belongs_to :that
|
5
4
|
has_many :foo_bars
|
6
5
|
has_many :bars, :through => :foo_bars
|
7
6
|
has_one :noob
|
8
7
|
end
|
8
|
+
|
9
9
|
class Bar < ActiveRecord::Base
|
10
10
|
has_many :foo_bars
|
11
11
|
has_many :foos, :through => :foo_bars
|
12
12
|
end
|
13
|
+
|
13
14
|
describe ConnectionManager::Associations do
|
14
15
|
|
15
16
|
it "should add associations as keys to @defined_associations" do
|
@@ -10,20 +10,20 @@ describe ConnectionManager::Connections do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
context '#
|
13
|
+
context '#clean_db_name' do
|
14
14
|
context "when name is not just the Rails.env" do
|
15
15
|
it "should remove the Rails.env from the string" do
|
16
|
-
ConnectionManager::Connections.
|
16
|
+
ConnectionManager::Connections.clean_db_name("my_database_test").should eql("my_database")
|
17
17
|
end
|
18
18
|
end
|
19
19
|
context "when the name is only the Rails.env" do
|
20
20
|
it "should use the name of the database and remove the Rails.env" do
|
21
21
|
ConnectionManager::Connections.stubs(:database_name_from_yml).returns("my_database_test")
|
22
|
-
ConnectionManager::Connections.
|
22
|
+
ConnectionManager::Connections.clean_db_name("test").should eql("my_database")
|
23
23
|
end
|
24
24
|
it "should account for sqlite3 database name" do
|
25
25
|
ConnectionManager::Connections.stubs(:database_name_from_yml).returns("db/my_database_test.sqlite3")
|
26
|
-
ConnectionManager::Connections.
|
26
|
+
ConnectionManager::Connections.clean_db_name("test").should eql("my_database")
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -50,7 +50,7 @@ describe ConnectionManager::Connections do
|
|
50
50
|
before(:all) do
|
51
51
|
# Make sure connections recreated in other tests do not presist to tests tests
|
52
52
|
ConnectionManager::Connections.all.clear
|
53
|
-
ConnectionManager::Connections.
|
53
|
+
ConnectionManager::Connections.secondary_connections.clear
|
54
54
|
|
55
55
|
#Initialize
|
56
56
|
ConnectionManager::Connections.initialize(:env => 'test')
|
@@ -58,18 +58,18 @@ describe ConnectionManager::Connections do
|
|
58
58
|
|
59
59
|
context '#all' do
|
60
60
|
it "should return the database.yml entries for the current rails environment" do
|
61
|
-
ConnectionManager::Connections.all.should eql(["CmConnection",
|
62
|
-
"Slave1CmConnection", "Slave2CmConnection"])
|
61
|
+
ConnectionManager::Connections.all.should eql(["CmConnection",
|
62
|
+
"Slave1CmConnection", "Slave2CmConnection", "Shard1CmConnection"])
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
context '#
|
66
|
+
context '#secondary_connections' do
|
67
67
|
it "should return a hash where the keys are the generic undescored names for all connections" do
|
68
|
-
ConnectionManager::Connections.
|
69
|
-
should eql([:cm, :slave_cm])
|
68
|
+
ConnectionManager::Connections.secondary_connections.keys.
|
69
|
+
should eql([:cm, :slave_cm, :shard_cm])
|
70
70
|
end
|
71
71
|
it "should return a hash where the values are an array of connection class names as strings" do
|
72
|
-
first_value = ConnectionManager::Connections.
|
72
|
+
first_value = ConnectionManager::Connections.secondary_connections.values.first
|
73
73
|
first_value.class.should eql(Array)
|
74
74
|
defined?((ConnectionManager::Connections.class_eval(first_value[0]))).should be_true
|
75
75
|
end
|
@@ -86,8 +86,7 @@ describe ConnectionManager::Connections do
|
|
86
86
|
it "should have a super class of ActiveRecord::Base" do
|
87
87
|
ConnectionManager::Connections::MyConnectionClass.superclass.should eql(ActiveRecord::Base)
|
88
88
|
end
|
89
|
-
end
|
90
|
-
|
89
|
+
end
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ConnectionManager::MethodRecorder do
|
4
|
+
before(:each) do
|
5
|
+
class Fruit < ActiveRecord::Base
|
6
|
+
#include ConnectionManager::MethodRecorder
|
7
|
+
def self.shards
|
8
|
+
ConnectionManager::MethodRecorder.new([self])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
context 'shards'do
|
13
|
+
it "it should record methods" do
|
14
|
+
a = Fruit.shards.select('fruits.*').where(:id => 1).order('created_at').first
|
15
|
+
a.recordings.should eql({:select => ['fruits.*'], :where => [:id =>1], :order => ['created_at'], :first => []})
|
16
|
+
end
|
17
|
+
|
18
|
+
context '#execute' do
|
19
|
+
it "should return an array of results" do
|
20
|
+
a = Fruit.shards.first.execute
|
21
|
+
a.should be_a_kind_of(Array)
|
22
|
+
end
|
23
|
+
it "should execute the active record methods on the the provided class" do
|
24
|
+
fruit = Factory.create(:fruit)
|
25
|
+
class_to_call = Fruit
|
26
|
+
a = class_to_call.shards.where(:id => fruit.id).first.execute
|
27
|
+
a[0].should be_a_kind_of(class_to_call)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not matter how the where statement is formated" do
|
31
|
+
fruit = Factory.create(:fruit)
|
32
|
+
a = Fruit.shards.where(:id => fruit.id).first.execute
|
33
|
+
b = Fruit.shards.where(['id = ?', fruit.id]).first.execute
|
34
|
+
c = Fruit.shards.where('id = ?', fruit.id).first.execute
|
35
|
+
(a == b && b == c).should be_true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe ConnectionManager::
|
3
|
+
describe ConnectionManager::SecondaryConnectionBuilder do
|
4
4
|
|
5
5
|
context '#database_name' do
|
6
6
|
it "should return the name of the database the model is using" do
|
@@ -11,28 +11,28 @@ describe ConnectionManager::ReplicationBuilder do
|
|
11
11
|
context '#other_association_options' do
|
12
12
|
|
13
13
|
it "should add :class_name options set to the replication subclass if :class_name is blank" do
|
14
|
-
options = Fruit.
|
14
|
+
options = Fruit.secondary_association_options(:has_one, :plant, 'Slave')
|
15
15
|
options[:class_name].should eql("Plant::Slave")
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should append :class_name with the replication subclass if :class_name is not bank" do
|
19
|
-
options = Fruit.
|
19
|
+
options = Fruit.secondary_association_options(:has_one, :plant, 'Slave', :class_name => 'Plant')
|
20
20
|
options[:class_name].should eql("Plant::Slave")
|
21
21
|
end
|
22
22
|
|
23
23
|
context "has_one or has_many" do
|
24
24
|
it "should add the :foreign_key if the :foreign_key options is not present" do
|
25
|
-
options = Fruit.
|
25
|
+
options = Fruit.secondary_association_options(:has_one, :plant, 'Slave')
|
26
26
|
options[:foreign_key].should eql('fruit_id')
|
27
|
-
options = Fruit.
|
27
|
+
options = Fruit.secondary_association_options(:has_many, :plant, 'Slave')
|
28
28
|
options[:foreign_key].should eql('fruit_id')
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
context '#
|
33
|
+
context '#secondary_connection_classes' do
|
34
34
|
it "should return the :using array with the array elements classified and append with Connection" do
|
35
|
-
Fruit.
|
35
|
+
Fruit.secondary_connection_classes({:using => ['slave_1_test_db','slave_2_test_db']}).
|
36
36
|
should eql(["Slave1TestDbConnection", "Slave2TestDbConnection"])
|
37
37
|
end
|
38
38
|
|
@@ -40,7 +40,7 @@ describe ConnectionManager::ReplicationBuilder do
|
|
40
40
|
|
41
41
|
context '#replicated' do
|
42
42
|
it "should raise an exception if no replication_connection_classes are found" do
|
43
|
-
Fruit.stubs(:
|
43
|
+
Fruit.stubs(:secondary_connection_classes).returns([])
|
44
44
|
lambda { Fruit.replicated }.should raise_error
|
45
45
|
end
|
46
46
|
|
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: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-12-
|
12
|
+
date: 2011-12-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement: &
|
16
|
+
requirement: &70148774706040 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70148774706040
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sqlite3
|
27
|
-
requirement: &
|
27
|
+
requirement: &70148774705620 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70148774705620
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &70148774705160 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70148774705160
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: autotest
|
49
|
-
requirement: &
|
49
|
+
requirement: &70148774704740 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70148774704740
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: mocha
|
60
|
-
requirement: &
|
60
|
+
requirement: &70148774704320 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70148774704320
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: factory_girl
|
71
|
-
requirement: &
|
71
|
+
requirement: &70148774703900 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70148774703900
|
80
80
|
description: Simplifies connecting to Muliple and Replication databases with rails
|
81
81
|
and active_record
|
82
82
|
email:
|
@@ -97,16 +97,18 @@ files:
|
|
97
97
|
- lib/connection_manager/associations.rb
|
98
98
|
- lib/connection_manager/connection_manager_railtie.rb
|
99
99
|
- lib/connection_manager/connections.rb
|
100
|
-
- lib/connection_manager/
|
100
|
+
- lib/connection_manager/method_recorder.rb
|
101
|
+
- lib/connection_manager/secondary_connection_builder.rb
|
101
102
|
- lib/connection_manager/version.rb
|
102
103
|
- spec/database.yml
|
103
104
|
- spec/factories.rb
|
104
105
|
- spec/helpers/database_spec_helper.rb
|
105
106
|
- spec/helpers/models_spec_helper.rb
|
106
|
-
- spec/integration/
|
107
|
+
- spec/integration/secondary_connection_builder_spec.rb
|
107
108
|
- spec/lib/associations_spec.rb
|
108
109
|
- spec/lib/connections_spec.rb
|
109
|
-
- spec/lib/
|
110
|
+
- spec/lib/method_recorder_spec.rb
|
111
|
+
- spec/lib/secondary_connection_builder_spec.rb
|
110
112
|
- spec/spec.opts
|
111
113
|
- spec/spec_helper.rb
|
112
114
|
homepage: ''
|
@@ -139,9 +141,10 @@ test_files:
|
|
139
141
|
- spec/factories.rb
|
140
142
|
- spec/helpers/database_spec_helper.rb
|
141
143
|
- spec/helpers/models_spec_helper.rb
|
142
|
-
- spec/integration/
|
144
|
+
- spec/integration/secondary_connection_builder_spec.rb
|
143
145
|
- spec/lib/associations_spec.rb
|
144
146
|
- spec/lib/connections_spec.rb
|
145
|
-
- spec/lib/
|
147
|
+
- spec/lib/method_recorder_spec.rb
|
148
|
+
- spec/lib/secondary_connection_builder_spec.rb
|
146
149
|
- spec/spec.opts
|
147
150
|
- spec/spec_helper.rb
|