connection_manager 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- connection_manager (0.2.0)
4
+ connection_manager (0.2.1)
5
5
  activerecord (~> 3.0)
6
6
 
7
7
  GEM
@@ -31,14 +31,15 @@ GEM
31
31
  mocha (0.10.0)
32
32
  metaclass (~> 0.0.1)
33
33
  multi_json (1.0.4)
34
- rspec (2.7.0)
35
- rspec-core (~> 2.7.0)
36
- rspec-expectations (~> 2.7.0)
37
- rspec-mocks (~> 2.7.0)
38
- rspec-core (2.7.1)
39
- rspec-expectations (2.7.0)
34
+ mysql2 (0.3.11)
35
+ rspec (2.8.0)
36
+ rspec-core (~> 2.8.0)
37
+ rspec-expectations (~> 2.8.0)
38
+ rspec-mocks (~> 2.8.0)
39
+ rspec-core (2.8.0)
40
+ rspec-expectations (2.8.0)
40
41
  diff-lcs (~> 1.1.2)
41
- rspec-mocks (2.7.0)
42
+ rspec-mocks (2.8.0)
42
43
  sqlite3 (1.3.5)
43
44
  tzinfo (0.3.31)
44
45
 
@@ -50,5 +51,6 @@ DEPENDENCIES
50
51
  connection_manager!
51
52
  factory_girl
52
53
  mocha
54
+ mysql2
53
55
  rspec
54
56
  sqlite3
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency 'autotest'
24
24
  s.add_development_dependency 'mocha'
25
25
  s.add_development_dependency 'factory_girl'
26
+ s.add_development_dependency 'mysql2'
26
27
  end
@@ -15,6 +15,12 @@ module ConnectionManager
15
15
  @env = env
16
16
  end
17
17
 
18
+ def env_regex(with_underscore=true)
19
+ s = "#{env}$"
20
+ s.insert(0,"\_") if with_underscore
21
+ Regexp.new("(#{s})")
22
+ end
23
+
18
24
  # Get the current environment if defined
19
25
  # Check for Rails, check for RACK_ENV, default to 'development'
20
26
  def fetch_env
@@ -27,7 +33,7 @@ module ConnectionManager
27
33
  # is blank it grabs all the connection keys
28
34
  def connection_keys
29
35
  @connection_keys ||= ActiveRecord::Base.configurations.keys.
30
- select{|n| n.match(Regexp.new("(#{env}$)"))}
36
+ select{|n| n.match(env_regex(false))}
31
37
  end
32
38
 
33
39
  # Contains all the connection classes built
@@ -48,12 +54,12 @@ module ConnectionManager
48
54
  def clean_sqlite_db_name(name,remove_env=true)
49
55
  new_name = "#{name}".gsub(/(\.sqlite3$)/,'')
50
56
  new_name = new_name.split("/").last
51
- new_name.gsub!(Regexp.new("(\_#{env}$)"),'') if remove_env
57
+ new_name.gsub!(env_regex,'') if remove_env
52
58
  new_name
53
59
  end
54
60
 
55
61
  def clean_db_name(name)
56
- new_name = "#{name}".gsub(Regexp.new("#{env}$"),'')
62
+ new_name = "#{name}".gsub(env_regex(false),'')
57
63
  if new_name.blank?
58
64
  new_name = "#{database_name_from_yml(name)}"
59
65
  end
@@ -64,7 +70,7 @@ module ConnectionManager
64
70
  # Given an connection key name from the database.yml, returns the string
65
71
  # equivelent of the class name for that entry.
66
72
  def connection_class_name(name_from_yml)
67
- new_class_name = clean_db_name(name_from_yml)
73
+ new_class_name = clean_db_name(name_from_yml)
68
74
  new_class_name = new_class_name.gsub(/\_/,' ').titleize.gsub(/ /,'')
69
75
  new_class_name << "Connection"
70
76
  new_class_name
@@ -84,7 +90,7 @@ module ConnectionManager
84
90
  end
85
91
 
86
92
  def available_secondary_connections(rep_collection_key)
87
- secondary_connections[(rep_collection_key.gsub(Regexp.new("(\_#{env}$)"),'')).to_sym]
93
+ secondary_connections[(rep_collection_key.gsub(env_regex,'')).to_sym]
88
94
  end
89
95
 
90
96
  # Sets class instance attributes, then builds connection classes, while populating
@@ -94,8 +100,8 @@ module ConnectionManager
94
100
  send("#{k.to_s}=",v)
95
101
  end
96
102
  connection_keys.each do |connection|
97
- new_connection = connection_class_name(connection)
98
- add_secondary_connection(connection,new_connection)
103
+ new_connection = connection_class_name(connection)
104
+ add_secondary_connection(connection,new_connection)
99
105
  build_connection_class(new_connection,connection)
100
106
  end
101
107
  all
@@ -109,7 +115,6 @@ module ConnectionManager
109
115
  end
110
116
  new_connection_class = Object.const_set(class_name, klass)
111
117
  new_connection_class.establish_connection(connection_key)
112
-
113
118
  (const_set class_name, new_connection_class)
114
119
  all << class_name
115
120
  end
@@ -49,37 +49,43 @@ module ConnectionManager
49
49
  build_secondary_connections(options)
50
50
  end
51
51
 
52
- def sharded(*settings)
52
+ def shard(*settings)
53
53
  options = {:name => "shard", :readonly => false, :shards => true}.merge(settings.extract_options!)
54
54
  build_secondary_connections(options)
55
55
  end
56
-
56
+
57
+ def child_connection_class?
58
+ false
59
+ end
57
60
  # Adds subclass with the class name of the type provided in the options, which
58
61
  # defaults to 'slave' if blank, that uses the connection from a connection class.
59
62
  # If :database option is blank?, replicated will assume the database.yml has
60
63
  # slave connections defined as: slave_database_name_test or slave_1_database_name_test,
61
64
  # where slave_1 is the secondary instance, 'database_name' is the actual
62
65
  # name of the database and '_test' is the Rails environment
63
- def build_secondary_connections(options={})
64
- connection_classes = secondary_connection_classes(options)
65
- if connection_classes.blank?
66
- raise ArgumentError, " a secondary connection was not found. Check your database.yml."
67
- else
68
- connection_methods = []
69
- connection_classes.each do |c|
70
- under_scored = c.underscore
71
- method_name = under_scored.split("_")[0]
72
- method_name = method_name.insert(method_name.index(/\d/),"_")
73
- class_name = method_name.classify
74
- connection_methods << method_name.to_sym
75
- build_secondary_class(class_name,c,options)
76
- build_single_secondary_method(method_name,class_name)
77
- set_table_name_for_joins
66
+ def build_secondary_connections(options={})
67
+ unless name.match(/\:\:/)
68
+ connection_classes = secondary_connection_classes(options)
69
+ sub_classes = []
70
+ if connection_classes.blank?
71
+ raise ArgumentError, " a secondary connection was not found. Check your database.yml."
72
+ else
73
+ connection_methods = []
74
+ connection_classes.each do |c|
75
+ under_scored = c.underscore
76
+ method_name = under_scored.split("_")[0]
77
+ method_name = method_name.insert(method_name.index(/\d/),"_")
78
+ class_name = method_name.classify
79
+ connection_methods << method_name.to_sym
80
+ build_secondary_class(class_name,c,options)
81
+ build_single_secondary_method(method_name,class_name)
82
+ #set_table_name_for_joins
83
+ sub_classes << "#{self.name}::#{class_name}".constantize if options[:shards]
84
+ end
78
85
  end
86
+ build_slaves_method(connection_methods) if options[:replication]
87
+ build_shards_method(sub_classes) if options[:shards]
79
88
  end
80
-
81
- build_slaves_method(connection_methods) if options[:replication]
82
- build_shards_method(connection_methods) if options[:shards]
83
89
  end
84
90
 
85
91
  # Creats a subclass that inherets from the model. The default model_name
@@ -93,38 +99,50 @@ module ConnectionManager
93
99
  # User::Slave2.where(:id => 2).first => returns results from slave_2 database
94
100
  # User::Shard1.where(:id => 2).first => returns results from slave_1 database
95
101
  def build_secondary_class(class_name,connection_name,options)
96
- class_eval <<-STR, __FILE__, __LINE__
97
- class #{class_name} < self
98
- #{build_secondary_associations(class_name)}
102
+ klass = Class.new(self) do
103
+ class << self
104
+ def model_name
105
+ ActiveModel::Name.new(superclass)
106
+ end
107
+ def child_connection_class?
108
+ true
109
+ end
110
+ end
111
+
112
+ if (options[:name] == "readonly" || options[:readonly])
113
+ def readonly?
114
+ true
115
+ end
116
+ end
117
+ end
118
+
119
+ sub_class = const_set(class_name, klass)
120
+ sub_class.build_secondary_associations(class_name)
121
+ sub_class.class_eval <<-STR, __FILE__, __LINE__
99
122
  class << self
100
123
  def connection
101
124
  Connections::#{connection_name}.connection
102
125
  end
103
- def model_name
104
- ActiveModel::Name.new(#{name})
105
- end
106
126
  end
107
- #{'def readonly?; true; end;' if (options[:name] == "readonly" || options[:readonly])}
108
- end
109
127
  STR
128
+
129
+ sub_class
110
130
  end
111
131
 
112
- def set_table_name_for_joins
113
- self.table_name_prefix = "#{database_name}." unless database_name.match(/\.sqlite3$/)
114
- end
132
+ # def set_table_name_for_joins
133
+ # self.table_name_prefix = "#{database_name}." unless database_name.match(/\.sqlite3$/)
134
+ # end
115
135
 
116
136
  # Adds as class method to call a specific secondary conneciton.
117
137
  # Usage:
118
138
  # User.slave_1.where(:id => 2).first => returns results from slave_1 database
119
139
  # User.slave_2.where(:id => 2).first => returns results from slave_2 database
120
140
  def build_single_secondary_method(method_name,class_name)
121
- class_eval <<-STR, __FILE__, __LINE__
122
- class << self
123
- def #{method_name}
124
- self::#{class_name}
125
- end
126
- end
127
- STR
141
+ self.class.instance_eval do
142
+ define_method method_name.to_s do
143
+ "#{name}::#{class_name}".constantize
144
+ end
145
+ end
128
146
  end
129
147
 
130
148
  # add a class method that shifts through available connections methods
@@ -132,35 +150,27 @@ module ConnectionManager
132
150
  # Usage:
133
151
  # User.slave.where(:id => 2).first => can return results from slave_1 or slave_2
134
152
  def build_slaves_method(connection_methods)
135
- class_eval <<-STR, __FILE__, __LINE__
136
- @connection_methods = #{connection_methods}
137
- class << self
138
- def slaves
153
+ @connection_methods = connection_methods
154
+ self.class.instance_eval do
155
+ define_method 'slaves' do
139
156
  current = @connection_methods.shift
140
157
  @connection_methods << current
141
158
  send(current)
142
159
  end
143
- alias :slave :slaves
144
- def connection_methods
145
- @connection_methods
146
- end
147
- end
148
- STR
160
+ alias_method :slave, :slaves
161
+ end
149
162
  end
150
163
 
151
164
  # add a class method that shifts through available connections methods
152
165
  # on each call.
153
166
  # Usage:
154
167
  # 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)
168
+ def build_shards_method(connection_classes)
169
+ self.class.instance_eval do
170
+ define_method 'shards' do
171
+ ConnectionManager::MethodRecorder.new(connection_classes)
161
172
  end
162
- end
163
- STR
173
+ end
164
174
  end
165
175
  end
166
176
  end
@@ -1,4 +1,4 @@
1
1
  module ConnectionManager
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
4
4
 
@@ -1,6 +1,6 @@
1
1
  class TestDB
2
- def self.connect
3
- ActiveRecord::Base.configurations = YAML::load(File.open(File.join(File.dirname(__FILE__),'..','database.yml')))
2
+ def self.connect(driver='sqlite')
3
+ ActiveRecord::Base.configurations = YAML::load(File.open(File.join(File.dirname(__FILE__),'..',"#{driver}_database.yml")))
4
4
  ActiveRecord::Base.establish_connection('test')
5
5
  end
6
6
  def self.clean
@@ -18,7 +18,8 @@ end
18
18
  class TestMigrations < ActiveRecord::Migration
19
19
 
20
20
  # all the ups
21
- def self.up
21
+ def self.up(connection_name='test')
22
+ ActiveRecord::Base.establish_connection(connection_name)
22
23
  begin
23
24
  create_table :foos do |t|
24
25
  t.string :name
@@ -54,7 +55,8 @@ class TestMigrations < ActiveRecord::Migration
54
55
 
55
56
 
56
57
  # all the downs
57
- def self.down
58
+ def self.down(connection_name='test')
59
+ ActiveRecord::Base.establish_connection(connection_name)
58
60
  begin
59
61
  [:foos,:fruits,:baskets,:fruit_baskets,:regions,:types].each do |t|
60
62
  drop_table t
@@ -33,6 +33,7 @@ describe ConnectionManager::SecondaryConnectionBuilder do
33
33
 
34
34
  context "subclasses" do
35
35
  it "should have a superclass of the parent class" do
36
+
36
37
  Fruit::Slave1.superclass.should eql(Fruit)
37
38
  end
38
39
  end
@@ -94,7 +95,7 @@ describe ConnectionManager::SecondaryConnectionBuilder do
94
95
  end
95
96
  context "model_name for slave" do
96
97
  it "should return the supers model_name" do
97
- Fruit.slave.model_name.should eql(Fruit.model_name)
98
+ Fruit.slave_1.model_name.should eql(Fruit.model_name)
98
99
  end
99
100
 
100
101
  it "should not interfear with inheritance" do
@@ -102,7 +103,6 @@ describe ConnectionManager::SecondaryConnectionBuilder do
102
103
  class MyFruit < Fruit
103
104
  replicated
104
105
  end
105
-
106
106
  Fruit.model_name.should_not eql(MyFruit.model_name)
107
107
  MyFruit.model_name.should eql("MyFruit")
108
108
  MyFruit.model_name.respond_to?(:plural).should be_true
@@ -1,13 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ConnectionManager::MethodRecorder do
4
- before(:each) do
4
+ before(:all) do
5
+ TestMigrations.up('shard_1_cm_test')
6
+ ConnectionManager::Connections.initialize(:env => 'test')
5
7
  class Fruit < ActiveRecord::Base
6
- #include ConnectionManager::MethodRecorder
7
- def self.shards
8
- ConnectionManager::MethodRecorder.new([self])
9
- end
8
+ shard(:using => ["shard_1_cm_test"])
10
9
  end
10
+
11
11
  end
12
12
  context 'shards'do
13
13
  it "it should record methods" do
@@ -36,4 +36,8 @@ describe ConnectionManager::MethodRecorder do
36
36
  end
37
37
  end
38
38
  end
39
+ after(:all) do
40
+ TestMigrations.down('shard_1_cm_test')
41
+ ActiveRecord::Base.establish_connection('test')
42
+ end
39
43
  end
@@ -4,7 +4,7 @@ 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
7
- Fruit.database_name.should eql('spec/cm_test.sqlite3')
7
+ Fruit.database_name.should eql('cm_test')
8
8
  end
9
9
  end
10
10
 
@@ -0,0 +1,25 @@
1
+ # Warning: The database defined as "test" will be erased and
2
+ # re-generated from your development database when you run "rake".
3
+ # Do not set this db to the same as development or production.
4
+ common: &common
5
+ adapter: mysql2
6
+ username: root
7
+ password: some_password
8
+ pool: 100
9
+ timeout: 5000
10
+
11
+ test:
12
+ <<: *common
13
+ database: cm_test
14
+
15
+ slave_1_cm_test:
16
+ <<: *common
17
+ database: cm_test
18
+
19
+ slave_2_cm_test:
20
+ <<: *common
21
+ database: cm_test
22
+
23
+ shard_1_cm_test:
24
+ <<: *common
25
+ database: legacy_cm_test
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,7 @@ require 'active_record'
5
5
  require 'factory_girl'
6
6
  require 'helpers/database_spec_helper'
7
7
 
8
- TestDB.connect
8
+ TestDB.connect('mysql2')
9
9
  TestMigrations.up
10
10
  FactoryGirl.find_definitions
11
11
 
File without changes
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.2.0
4
+ version: 0.2.1
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-27 00:00:00.000000000Z
12
+ date: 2012-01-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &70148774706040 !ruby/object:Gem::Requirement
16
+ requirement: &70350833047080 !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: *70148774706040
24
+ version_requirements: *70350833047080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sqlite3
27
- requirement: &70148774705620 !ruby/object:Gem::Requirement
27
+ requirement: &70350833046660 !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: *70148774705620
35
+ version_requirements: *70350833046660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70148774705160 !ruby/object:Gem::Requirement
38
+ requirement: &70350833046200 !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: *70148774705160
46
+ version_requirements: *70350833046200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: autotest
49
- requirement: &70148774704740 !ruby/object:Gem::Requirement
49
+ requirement: &70350833045780 !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: *70148774704740
57
+ version_requirements: *70350833045780
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: mocha
60
- requirement: &70148774704320 !ruby/object:Gem::Requirement
60
+ requirement: &70350833045360 !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: *70148774704320
68
+ version_requirements: *70350833045360
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: factory_girl
71
- requirement: &70148774703900 !ruby/object:Gem::Requirement
71
+ requirement: &70350833044940 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,18 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70148774703900
79
+ version_requirements: *70350833044940
80
+ - !ruby/object:Gem::Dependency
81
+ name: mysql2
82
+ requirement: &70350833044520 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70350833044520
80
91
  description: Simplifies connecting to Muliple and Replication databases with rails
81
92
  and active_record
82
93
  email:
@@ -100,7 +111,6 @@ files:
100
111
  - lib/connection_manager/method_recorder.rb
101
112
  - lib/connection_manager/secondary_connection_builder.rb
102
113
  - lib/connection_manager/version.rb
103
- - spec/database.yml
104
114
  - spec/factories.rb
105
115
  - spec/helpers/database_spec_helper.rb
106
116
  - spec/helpers/models_spec_helper.rb
@@ -109,8 +119,10 @@ files:
109
119
  - spec/lib/connections_spec.rb
110
120
  - spec/lib/method_recorder_spec.rb
111
121
  - spec/lib/secondary_connection_builder_spec.rb
122
+ - spec/mysql2_database.yml
112
123
  - spec/spec.opts
113
124
  - spec/spec_helper.rb
125
+ - spec/sqlite_database.yml
114
126
  homepage: ''
115
127
  licenses: []
116
128
  post_install_message:
@@ -137,7 +149,6 @@ specification_version: 3
137
149
  summary: Simplifies connecting to Muliple and Replication databases with rails and
138
150
  active_record
139
151
  test_files:
140
- - spec/database.yml
141
152
  - spec/factories.rb
142
153
  - spec/helpers/database_spec_helper.rb
143
154
  - spec/helpers/models_spec_helper.rb
@@ -146,5 +157,7 @@ test_files:
146
157
  - spec/lib/connections_spec.rb
147
158
  - spec/lib/method_recorder_spec.rb
148
159
  - spec/lib/secondary_connection_builder_spec.rb
160
+ - spec/mysql2_database.yml
149
161
  - spec/spec.opts
150
162
  - spec/spec_helper.rb
163
+ - spec/sqlite_database.yml