module DbCharmer::ActiveRecord::Relation::ConnectionRouting
Constants
- ALL_METHODS
- DB_CHARMER_ATTRIBUTES
- MASTER_METHODS
- SLAVE_METHODS
All the methods that could be querying the database
Public Class Methods
Need this to mimick alias_method_chain name generation (exists? => exists_with_db_charmer?)
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 128 def self.aliased_method_name(target, with) aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 "#{aliased_target}_#{with}_db_charmer#{punctuation}" end
Define the default relation connection + override all the query methods here
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 14 def self.included(base) init_attributes(base) init_routing(base) end
Define our attributes + spawn methods shit needs to be changed to make sure our accessors are copied over to the new instances
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 20 def self.init_attributes(base) DB_CHARMER_ATTRIBUTES.each do |attr| base.send(:attr_accessor, attr) end # Override spawn methods base.alias_method_chain :except, :db_charmer base.alias_method_chain :only, :db_charmer end
Override all query methods
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 31 def self.init_routing(base) ALL_METHODS.each do |meth| base.alias_method_chain meth, :db_charmer end # Special case: for normal selects we go to the slave, but for selects with a lock we should use master base.alias_method_chain :to_a, :db_charmer end
Public Instance Methods
Make sure we get the right connection here
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 74 def connection @klass.on_db(db_charmer_connection).connection end
Copy our accessors from one instance to another
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 55 def copy_db_charmer_options(src, dst) DB_CHARMER_ATTRIBUTES.each do |attr| dst.send("#{attr}=".to_sym, src.send(attr)) end end
Copy db_charmer attributes in addition to what they’re copying
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 41 def except_with_db_charmer(*args) except_without_db_charmer(*args).tap do |result| copy_db_charmer_options(self, result) end end
Connection switching (changes the default relation connection)
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 62 def on_db(con, &block) if block_given? @klass.on_db(con, &block) else clone.tap do |result| result.db_charmer_connection = con result.db_charmer_connection_is_forced = true end end end
Copy db_charmer attributes in addition to what they’re copying
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 48 def only_with_db_charmer(*args) only_without_db_charmer(*args).tap do |result| copy_db_charmer_options(self, result) end end
Selects preferred destination (master/slave/default) for a query
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 79 def select_destination(method, recommendation = :default) # If this relation was created within a forced connection block (e.g Model.on_db(:foo).relation) # Then we should use that connection everywhere except cases when a model is slave-enabled # in those cases DML queries go to the master if db_charmer_connection_is_forced return :master if db_charmer_enable_slaves && MASTER_METHODS.member?(method) return :default end # If this relation is created from a slave-enabled model, let's do the routing if possible if db_charmer_enable_slaves return :slave if SLAVE_METHODS.member?(method) return :master if MASTER_METHODS.member?(method) else # Make sure we do not use recommended destination recommendation = :default end # If nothing else came up, let's use the default or recommended connection return recommendation end
Switch the model to default relation connection
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 102 def switch_connection_for_method(method, recommendation = nil) # Choose where to send the query destination ||= select_destination(method, recommendation) # What method to use on_db_method = [ :on_db, db_charmer_connection ] on_db_method = :on_master if destination == :master on_db_method = :first_level_on_slave if destination == :slave # Perform the query @klass.send(*on_db_method) do yield end end
For normal selects we go to the slave, but for selects with a lock we should use master
# File lib/db_charmer/rails3/active_record/relation/connection_routing.rb, line 118 def to_a_with_db_charmer(*args, &block) preferred_destination = :slave preferred_destination = :master if lock_value switch_connection_for_method(:to_a, preferred_destination) do to_a_without_db_charmer(*args, &block) end end