yam-db-charmer 1.7.01 → 1.7.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  /pkg
3
3
  .DS_Store
4
4
  /_site
5
+ *.swo
6
+ *.swp
data/CHANGES CHANGED
@@ -1,3 +1,11 @@
1
+ 1.7.1 (2012-04-22):
2
+
3
+ Beta feature: Rails 3.1 and 3.2 support
4
+
5
+ Thanks to the community (and Eugene Pimenov aka @libc in particular) we now have support
6
+ for Rails versions up to 3.2.1, including new migrations classes.
7
+
8
+ ----------------------------------------------------------------------------------------
1
9
  1.7.0 (2011-08-29):
2
10
 
3
11
  Beta feature: Rails 3 support
data/README.rdoc CHANGED
@@ -16,7 +16,7 @@ For more information on the project, you can check out our web site at http://ko
16
16
  == Installation
17
17
 
18
18
  There are two options when approaching +DbCharmer+ installation:
19
- * using the gem (recommended and the only way of using it with Rails 3.0+)
19
+ * using the gem (recommended and the only way of using it with Rails 3.2+)
20
20
  * install as a Rails plugin (works in Rails 2.x only)
21
21
 
22
22
  To install as a gem, add this to your Gemfile:
@@ -276,7 +276,7 @@ This option could be used to disable automated slave reads on your models so tha
276
276
  call <tt>on_slave</tt> or use other methods to enable slave reads when you need it. Example:
277
277
 
278
278
  class User < ActiveRecord::Base
279
- db_magic :slave => slave01, :forced_slave_reads => false
279
+ db_magic :slave => slave01, :force_slave_reads => false
280
280
  end
281
281
 
282
282
  2) <tt>force_slave_reads</tt> +ActionController+ class method. This method could be used to
@@ -582,17 +582,17 @@ the DbCharmer Users Group mailing list:
582
582
 
583
583
  == What Ruby and Rails implementations does it work for?
584
584
 
585
- We have a continuous integration setup for this gem on with Rails 2.2, 2.3 and 3.0 using a few
585
+ We have a continuous integration setup for this gem on with Rails 2.3, 3.0, 3.1 and 3.2 using a few
586
586
  different versions of Ruby. For more information about the build matrix please visit
587
587
  http://github.com/kovyrin/db-charmer-sandbox web site.
588
588
 
589
- In addition to CI testing, we use this gem in production on Scribd.com (one of the largest RoR
589
+ In addition to CI testing, this gem is used in production on Scribd.com (one of the largest RoR
590
590
  sites in the world) with Ruby Enterprise Edition and Rails 2.2, Rails 2.3, Sinatra and plain
591
591
  Rack applications.
592
592
 
593
- Starting with version 1.7.0 we support Rails 3.0, but until further notice we consider it a
593
+ Starting with version 1.7.0 we support Rails 3.0-3.2, but until further notice we consider it a
594
594
  beta-quality feature since we do not run any production software on this version of Rails. If you
595
- run your application on Rails 3.0, please contact the author.
595
+ run your application on Rails 3.x and having any issues with the gem, please contact the author.
596
596
 
597
597
 
598
598
  == Who are the authors?
@@ -605,8 +605,12 @@ Other contributors who have helped with the development of this library are (alp
605
605
  * Allen Madsen
606
606
  * Andrew Geweke
607
607
  * Ashley Martens
608
+ * Cauê Guerra
609
+ * David Dai
608
610
  * Dmytro Shteflyuk
609
611
  * Eric Lindvall
612
+ * Eugene Pimenov
613
+ * Jonathan Viney
610
614
  * Gregory Man
611
615
  * Michael Birk
612
616
  * Tyler McMullen
data/db-charmer.gemspec CHANGED
@@ -20,8 +20,8 @@ Gem::Specification.new do |s|
20
20
  s.extra_rdoc_files = [ 'LICENSE', 'README.rdoc' ]
21
21
 
22
22
  # Dependencies
23
- s.add_dependency 'activesupport', '< 3.1'
24
- s.add_dependency 'activerecord', '< 3.1'
23
+ s.add_dependency 'activesupport', '~> 3.0'
24
+ s.add_dependency 'activerecord', '~> 3.0'
25
25
 
26
26
  s.add_development_dependency 'rspec'
27
27
  s.add_development_dependency 'yard'
@@ -4,7 +4,7 @@ module DbCharmer
4
4
 
5
5
  module ClassMethods
6
6
  @@db_charmer_force_slave_reads_actions = {}
7
- def force_slave_reads(params)
7
+ def force_slave_reads(params = {})
8
8
  @@db_charmer_force_slave_reads_actions[self.name] = {
9
9
  :except => params[:except] ? [*params[:except]].map(&:to_s) : [],
10
10
  :only => params[:only] ? [*params[:only]].map(&:to_s) : []
@@ -55,7 +55,7 @@ module DbCharmer
55
55
 
56
56
  protected
57
57
 
58
- class_eval <<-EOF
58
+ class_eval <<-EOF, __FILE__, __LINE__+1
59
59
  def #{DISPATCH_METHOD}_with_forced_slave_reads(*args, &block)
60
60
  DbCharmer.with_controller(self) do
61
61
  #{DISPATCH_METHOD}_without_forced_slave_reads(*args, &block)
@@ -1,6 +1,7 @@
1
1
  module DbCharmer
2
2
  module ActiveRecord
3
3
  module ConnectionSwitching
4
+
4
5
  def establish_real_connection_if_exists(name, should_exist = false)
5
6
  name = name.to_s
6
7
 
@@ -34,11 +35,22 @@ module DbCharmer
34
35
  db_charmer_remapped_connection || db_charmer_connection_proxy || connection_without_magic
35
36
  end
36
37
  alias_method_chain :connection, :magic
38
+
39
+ def connection_pool_with_magic
40
+ abstract_connection_class = connection.abstract_connection_class rescue nil # respond_to? doesn't work on connection_proxy...
41
+ if abstract_connection_class
42
+ connection_handler.retrieve_connection_pool(abstract_connection_class) || connection_pool_without_magic
43
+ else
44
+ connection_pool_without_magic
45
+ end
46
+ end
47
+ alias_method_chain :connection_pool, :magic
37
48
  end
38
49
  end
39
50
 
40
51
  #-----------------------------------------------------------------------------------------------------------------
41
52
  def coerce_to_connection_proxy(conn, should_exist = true)
53
+ #Rails.logger.debug "coerce_to_connection_proxy: conn class=#{conn.class}"
42
54
  return nil if conn.nil?
43
55
 
44
56
  if conn.kind_of?(Symbol) || conn.kind_of?(String)
@@ -70,11 +82,16 @@ module DbCharmer
70
82
  db_charmer_connection_proxy.set_real_connection(new_conn)
71
83
  end
72
84
 
85
+ # Set schema name as table_name_prefix
86
+ set_schema_table_name_prefix(conn) if self.respond_to? :set_schema_table_name_prefix
87
+
88
+
73
89
  self.db_charmer_connection_proxy = new_conn
74
90
  self.hijack_connection!
75
91
 
76
92
  # self.reset_column_information
77
93
  end
94
+
78
95
 
79
96
  end
80
97
  end
@@ -38,9 +38,15 @@ module DbCharmer
38
38
  def setup_children_magic(opt)
39
39
  self.db_charmer_opts = opt.clone
40
40
 
41
- def self.inherited(child)
42
- child.db_magic(self.db_charmer_opts)
43
- super
41
+ unless self.respond_to?(:inherited_with_db_magic)
42
+ class << self
43
+ def inherited_with_db_magic(child)
44
+ o = inherited_without_db_magic(child)
45
+ child.db_magic(self.db_charmer_opts)
46
+ o
47
+ end
48
+ alias_method_chain :inherited, :db_magic
49
+ end
44
50
  end
45
51
  end
46
52
 
@@ -82,4 +88,3 @@ module DbCharmer
82
88
  end
83
89
  end
84
90
  end
85
-
@@ -3,23 +3,90 @@ module DbCharmer
3
3
  module Migration
4
4
  module MultiDbMigrations
5
5
 
6
- def self.extended(base)
7
- class << base
8
- alias_method_chain :migrate, :db_wrapper
6
+ def self.append_features(base)
7
+ return false if base < self
8
+ super
9
+ base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
10
+
11
+ base.class_eval do
12
+ if DbCharmer.rails31?
13
+ alias_method_chain :migrate, :db_wrapper
14
+ else
15
+ class << self
16
+ alias_method_chain :migrate, :db_wrapper
17
+ end
18
+ end
9
19
  end
10
20
  end
11
21
 
12
- @@multi_db_names = {}
13
- def multi_db_names
14
- @@multi_db_names[self.name] || @@multi_db_names['ActiveRecord::Migration']
15
- end
22
+ module ClassMethods
23
+ @@multi_db_names = {}
24
+ def multi_db_names
25
+ @@multi_db_names[self.name] || @@multi_db_names['ActiveRecord::Migration']
26
+ end
27
+
28
+ def multi_db_names=(names)
29
+ @@multi_db_names[self.name] = names
30
+ end
31
+
32
+ unless DbCharmer.rails31?
33
+ def migrate_with_db_wrapper(direction)
34
+ if names = multi_db_names
35
+ names.each do |multi_db_name|
36
+ on_db(multi_db_name) do
37
+ migrate_without_db_wrapper(direction)
38
+ end
39
+ end
40
+ else
41
+ migrate_without_db_wrapper(direction)
42
+ end
43
+ end
44
+
45
+ def on_db(db_name)
46
+ s = "Switching connection to "
47
+ if db_name.is_a?(Hash)
48
+ s << db_name[:connection_name]
49
+ s << ", schema #{db_name[:schema_name]}" if db_name[:schema_name]
50
+ else
51
+ s << db_name.inspect
52
+ end
53
+ announce s
54
+ # Switch connection
55
+ old_proxy = ::ActiveRecord::Base.db_charmer_connection_proxy
56
+ db_name = nil if db_name == :default
57
+ ::ActiveRecord::Base.switch_connection_to(db_name, DbCharmer.connections_should_exist?)
58
+ # Yield the block
59
+ yield
60
+ ensure
61
+ # Switch it back
62
+ ::ActiveRecord::Base.verify_active_connections!
63
+ announce "Switching connection back"
64
+ ::ActiveRecord::Base.switch_connection_to(old_proxy)
65
+ end
66
+ end
67
+
68
+ def db_magic(opts = {})
69
+ # Collect connections from all possible options
70
+ conns = [ opts[:connection], opts[:connections] ]
71
+ conns << shard_connections(opts[:sharded_connection]) if opts[:sharded_connection]
72
+
73
+ # Get a unique set of connections
74
+ conns = conns.flatten.compact.uniq
75
+ raise ArgumentError, "No connection name - no magic!" unless conns.any?
76
+
77
+ # Save connections
78
+ self.multi_db_names = conns
79
+ end
16
80
 
17
- def multi_db_names=(names)
18
- @@multi_db_names[self.name] = names
81
+ # Return a list of connections to shards in a sharded connection
82
+ def shard_connections(conn_name)
83
+ conn = DbCharmer::Sharding.sharded_connection(conn_name)
84
+ conn.shard_connections
85
+ end
19
86
  end
20
87
 
21
88
  def migrate_with_db_wrapper(direction)
22
- if names = multi_db_names
89
+ if names = self.class.multi_db_names
23
90
  names.each do |multi_db_name|
24
91
  on_db(multi_db_name) do
25
92
  migrate_without_db_wrapper(direction)
@@ -30,41 +97,52 @@ module DbCharmer
30
97
  end
31
98
  end
32
99
 
33
- def on_db(db_name)
34
- name = db_name.is_a?(Hash) ? db_name[:connection_name] : db_name.inspect
35
- announce "Switching connection to #{name}"
100
+ def record_on_db(db_name, block)
101
+ recorder = ::ActiveRecord::Migration::CommandRecorder.new(DbCharmer::ConnectionFactory.connect(db_name))
102
+ old_recorder, @connection = @connection, recorder
103
+ block.call
104
+ old_recorder.record :on_db, [db_name, @connection]
105
+ @connection = old_recorder
106
+ end
107
+
108
+ def replay_commands_on_db(name, commands)
109
+ on_db(name) do
110
+ commands.each do |cmd, args|
111
+ send(cmd, *args)
112
+ end
113
+ end
114
+ end
115
+
116
+ def on_db(db_name, &block)
117
+ if @connection.is_a?(::ActiveRecord::Migration::CommandRecorder)
118
+ record_on_db(db_name, block)
119
+ return
120
+ end
121
+
122
+ s = "Switching connection to "
123
+ if db_name.is_a?(Hash)
124
+ s << db_name[:connection_name]
125
+ s << ", schema #{db_name[:schema_name]}" if db_name[:schema_name]
126
+ else
127
+ s << db_name.inspect
128
+ end
129
+ announce s
36
130
  # Switch connection
37
- old_proxy = ::ActiveRecord::Base.db_charmer_connection_proxy
131
+ old_connection, old_proxy = @connection, ::ActiveRecord::Base.db_charmer_connection_proxy
38
132
  db_name = nil if db_name == :default
39
133
  ::ActiveRecord::Base.switch_connection_to(db_name, DbCharmer.connections_should_exist?)
40
134
  # Yield the block
41
- yield
135
+ ::ActiveRecord::Base.connection_pool.with_connection do |conn|
136
+ @connection = conn
137
+ yield
138
+ end
42
139
  ensure
140
+ @connection = old_connection
43
141
  # Switch it back
44
142
  ::ActiveRecord::Base.verify_active_connections!
45
143
  announce "Switching connection back"
46
144
  ::ActiveRecord::Base.switch_connection_to(old_proxy)
47
145
  end
48
-
49
- def db_magic(opts = {})
50
- # Collect connections from all possible options
51
- conns = [ opts[:connection], opts[:connections] ]
52
- conns << shard_connections(opts[:sharded_connection]) if opts[:sharded_connection]
53
-
54
- # Get a unique set of connections
55
- conns = conns.flatten.compact.uniq
56
- raise ArgumentError, "No connection name - no magic!" unless conns.any?
57
-
58
- # Save connections
59
- self.multi_db_names = conns
60
- end
61
-
62
- # Return a list of connections to shards in a sharded connection
63
- def shard_connections(conn_name)
64
- conn = DbCharmer::Sharding.sharded_connection(conn_name)
65
- conn.shard_connections
66
- end
67
-
68
146
  end
69
147
  end
70
148
  end
@@ -29,7 +29,16 @@ module DbCharmer
29
29
  def on_db(con, proxy_target = nil)
30
30
  proxy_target ||= self
31
31
 
32
+ # This is for the block_schema_map method.
33
+ # Setting the table_name_prefix is done in switch_connection_to
34
+ # but we don't go through switch_connection_to when the connection is set
35
+ # outside of shard_for.
36
+ if self.respond_to? :set_schema_table_name_prefix
37
+ self.set_schema_table_name_prefix(con)
38
+ end
39
+
32
40
  # Chain call
41
+ #Rails.logger.debug "MultiDbProxy#on_db: con=#{con} proxy_target=#{proxy_target}"
33
42
  return OnDbProxy.new(proxy_target, con) unless block_given?
34
43
 
35
44
  # Block call
@@ -24,6 +24,14 @@ module DbCharmer
24
24
  @@connection_classes[connection_name] ||= establish_connection_to_db(connection_name, config)
25
25
  end
26
26
 
27
+ def self.reset_connection(connection_name)
28
+ connection_name = connection_name.to_s
29
+ if @@connection_classes[connection_name]
30
+ @@connection_classes[connection_name].disconnect!
31
+ @@connection_classes.delete(connection_name)
32
+ end
33
+ end
34
+
27
35
  # Establish connection with a specified name
28
36
  def self.establish_connection(connection_name, should_exist = true)
29
37
  abstract_class = generate_abstract_class(connection_name, should_exist)
@@ -12,9 +12,14 @@ module DbCharmer
12
12
  # Create a relation object and initialize its default connection
13
13
  def relation_with_db_charmer(*args, &block)
14
14
  relation_without_db_charmer(*args, &block).tap do |rel|
15
- rel.db_charmer_connection = self.connection
15
+ rel.db_charmer_connection = self.retrieve_connection
16
16
  rel.db_charmer_enable_slaves = self.db_charmer_slaves.any?
17
17
  rel.db_charmer_connection_is_forced = !db_charmer_top_level_connection?
18
+
19
+ # The relation may have been memoized at a time when the schema
20
+ # was different. Reset the schema here to use the value saved in the model
21
+ # (which might have been updated previously when fetching the connection).
22
+ rel.table.name = self.table_name
18
23
  end
19
24
  end
20
25
 
@@ -0,0 +1,11 @@
1
+ module DbCharmer
2
+ module ActiveRecord
3
+ module Migration
4
+ module CommandRecorder
5
+ def invert_on_db(args)
6
+ [:replay_commands_on_db, [args.first, args[1].inverse]]
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module DbCharmer
2
+ module ActiveRecord
3
+ module Preloader
4
+ module Association
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ alias_method_chain :build_scope, :db_magic
8
+ end
9
+
10
+ def build_scope_with_db_magic
11
+ if model.db_charmer_top_level_connection? || reflection.options[:polymorphic] ||
12
+ model.db_charmer_default_connection != klass.db_charmer_default_connection
13
+ build_scope_without_db_magic
14
+ else
15
+ build_scope_without_db_magic.on_db(model)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module DbCharmer
2
+ module ActiveRecord
3
+ module Preloader
4
+ module HasAndBelongsToMany
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ alias_method_chain :records_for, :db_magic
8
+ end
9
+
10
+ def records_for_with_db_magic(ids)
11
+ if model.db_charmer_top_level_connection? || reflection.options[:polymorphic] ||
12
+ model.db_charmer_default_connection != klass.db_charmer_default_connection
13
+ records_for_without_db_magic(ids)
14
+ else
15
+ klass.on_db(model) do
16
+ records_for_without_db_magic(ids)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end