Browse files

change query strategy based on adapter

  • Loading branch information...
1 parent 060fbd6 commit e7f5317ff9696e7e38c56d403ec822ee94aa8e24 @tenderlove tenderlove committed Jan 16, 2014
View
6 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -18,6 +18,12 @@ def to_sql(arel, binds = [])
end
end
+ # This is used in the StatementCache object. It returns an object that
+ # can be used to query the database repeatedly.
+ def cacheable_query(arel) # :nodoc:
+ ActiveRecord::StatementCache.query self, visitor, arel.ast
+ end
+
# Returns an ActiveRecord::Result instance.
def select_all(arel, name = nil, binds = [])
select(to_sql(arel, binds), name, binds)
View
4 activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -44,6 +44,10 @@ def initialize(connection, logger, connection_options, config)
configure_connection
end
+ def cacheable_query(arel)
+ ActiveRecord::StatementCache.partial_query self, visitor, arel.ast
+ end
+
MAX_INDEX_LENGTH_FOR_UTF8MB4 = 191
def initialize_schema_migrations_table
if @config[:encoding] == 'utf8mb4'
View
45 activerecord/lib/active_record/statement_cache.rb
@@ -16,6 +16,32 @@ module ActiveRecord
class StatementCache
Substitute = Struct.new :name
+ class Query
+ def initialize(connection, sql)
+ @connection = connection
+ @sql = sql
+ end
+
+ def sql_for(binds)
+ @sql
+ end
+ end
+
+ class PartialQuery < Query
+ def sql_for(binds)
+ @sql.gsub(/\?/) { @connection.quote(*binds.shift.reverse) }
+ end
+ end
+
+ def self.query(connection, visitor, ast)
+ Query.new connection, visitor.accept(ast)
+ end
+
+ def self.partial_query(connection, visitor, ast)
+ sql = visitor.accept(ast) { "?" }
+ PartialQuery.new connection, sql
+ end
+
class Params
def [](name); Substitute.new name; end
end
@@ -45,17 +71,22 @@ def initialize(block = Proc.new)
@sql = nil
@binds = nil
@block = block
+ @query_builder = nil
@params = Params.new
end
def execute(params)
rel = relation @params
- arel = rel.arel
- klass = rel.klass
- bv = binds rel
+ arel = rel.arel
+ klass = rel.klass
+ bind_map = binds rel
+ bind_values = bind_map.bind params
- klass.find_by_sql sql(klass, arel, bv), bv.bind(params)
+ builder = query_builder klass.connection, arel
+ sql = builder.sql_for bind_values
+
+ klass.find_by_sql sql, bind_values
end
alias :call :execute
@@ -64,6 +95,12 @@ def binds(rel)
@binds || @mutex.synchronize { @binds ||= BindMap.new rel.bind_values }
end
+ def query_builder(connection, arel)
+ @query_builder || @mutex.synchronize {
+ @query_builder ||= connection.cacheable_query(arel)
+ }
+ end
+
def sql(klass, arel, bv)
@sql || @mutex.synchronize {
@sql ||= klass.connection.to_sql arel, bv
View
1 activerecord/test/cases/statement_cache_test.rb
@@ -7,7 +7,6 @@
module ActiveRecord
class StatementCacheTest < ActiveRecord::TestCase
def setup
- skip if current_adapter?(:Mysql2Adapter)
@connection = ActiveRecord::Base.connection
end

0 comments on commit e7f5317

Please sign in to comment.