lib/replica.rb in replica-1.1.0 vs lib/replica.rb in replica-1.2.0

- old
+ new

@@ -1,145 +1,7 @@ require 'activerecord' +require 'replica/base' +require 'replica/association_collection' +require 'replica/connection_pool' -module ActiveRecord # :nodoc: - class Base # :nodoc: - module Replica - - # Executes queries using the slave database. Fails over to master if no slave is found. - # if you want to execute a block of code on the slave you can go: - # Account.with_slave do - # Account.first - # end - # the first account will be found on the slave DB - # - # For one-liners you can simply do - # Account.with_slave.first - # - # this is the same as: - # Account.with_replica(:slave) do - # Account.first - # end - def with_slave(&block) - with_replica(:slave, &block) - end - - # See with_slave - def with_master(&block) - with_replica(nil, &block) - end - - def with_slave_if(condition, &block) - condition ? with_slave(&block) : with_master(&block) - end - - def with_slave_unless(condition, &block) - with_slave_if(!condition, &block) - end - - # Name of the connection pool. Used by ConnectionHandler to retrieve the current connection pool. - def connection_pool_name # :nodoc: - replica = current_replica_name - if replica - "#{name}_#{replica}" - elsif self == ActiveRecord::Base - name - else - superclass.connection_pool_name - end - end - - # Specify which database to use. - # - # Example: - # database.yml - # test_slave: - # adapter: mysql - # ... - # - # Account.with_replica(:slave) { Account.count } - # Account.with_replica(:slave).count - # - def with_replica(replica_name, &block) - if block_given? - with_replica_block(replica_name, &block) - else - Proxy.new(self, replica_name) - end - end - - def with_replica_block(replica_name, &block) - old_replica_name = current_replica_name - begin - self.current_replica_name = replica_name - rescue ActiveRecord::AdapterNotSpecified => e - self.current_replica_name = old_replica_name - logger.warn("Failed to establish replica connection: #{e.message} - defaulting to master") - end - yield - ensure - self.current_replica_name = old_replica_name - end - - private - - def current_replica_name - Thread.current[replica_key] - end - - def current_replica_name=(new_replica_name) - Thread.current[replica_key] = new_replica_name - - establish_replica_connection(new_replica_name) unless connected_to_replica? - end - - def establish_replica_connection(replica_name) - name = replica_name ? "#{RAILS_ENV}_#{replica_name}" : RAILS_ENV - spec = configurations[name] - raise AdapterNotSpecified.new("No database defined by #{name} in database.yml") if spec.nil? - - connection_handler.establish_connection(connection_pool_name, ConnectionSpecification.new(spec, "#{spec['adapter']}_connection")) - end - - def connected_to_replica? - connection_handler.connection_pools.has_key?(connection_pool_name) - end - - def replica_key - @replica_key ||= "#{name}_replica" - end - - class Proxy - def initialize(target, replica) - @target = target - @replica = replica - end - - def method_missing(method, *args, &block) - @target.with_replica_block(@replica) { @target.send(method, *args, &block) } - end - end - end - end - Base.extend(Base::Replica) - - # The only difference here is that we use klass.connection_pool_name - # instead of klass.name as the pool key - module ConnectionAdapters # :nodoc: - class ConnectionHandler # :nodoc: - - def retrieve_connection_pool(klass) - pool = @connection_pools[klass.connection_pool_name] - return pool if pool - return nil if ActiveRecord::Base == klass - retrieve_connection_pool klass.superclass - end - - def remove_connection(klass) - pool = @connection_pools[klass.connection_pool_name] - @connection_pools.delete_if { |key, value| value == pool } - pool.disconnect! if pool - pool.spec.config if pool - end - - end - end -end +ActiveRecord::Base.extend ActiveRecord::Base::Replica +ActiveRecord::Associations::AssociationCollection.send(:include, ActiveRecord::Associations::AssociationCollection::Replica)