diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2014-04-14 16:26:28 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2014-04-14 16:26:28 -0700 |
commit | bd3b28f7f181dce53e872daa23dda101498b8fb4 (patch) | |
tree | 99ab0f92b5b3ff42525cab8d872393508a2b5c45 /activerecord/lib/active_record/associations | |
parent | 316ee25c25a64a2d82c284293a31804077b05d79 (diff) | |
download | rails-bd3b28f7f181dce53e872daa23dda101498b8fb4.tar.gz rails-bd3b28f7f181dce53e872daa23dda101498b8fb4.tar.bz2 rails-bd3b28f7f181dce53e872daa23dda101498b8fb4.zip |
cache scope building on associations
SQL statements for querying associations are now cached
Diffstat (limited to 'activerecord/lib/active_record/associations')
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 55 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/collection_association.rb | 16 |
2 files changed, 64 insertions, 7 deletions
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index bb889a8f3b..f1a3b23d5a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -1,12 +1,34 @@ module ActiveRecord module Associations class AssociationScope #:nodoc: - INSTANCE = new - def self.scope(association, connection) INSTANCE.scope association, connection end + class BindSubstitution + def initialize(block) + @block = block + end + + def bind_value(scope, column, value, alias_tracker) + substitute = alias_tracker.connection.substitute_at( + column, scope.bind_values.length) + scope.bind_values += [[column, @block.call(value)]] + substitute + end + end + + def self.create(&block) + block = block ? block : lambda { |val| val } + new BindSubstitution.new(block) + end + + def initialize(bind_substitution) + @bind_substitution = bind_substitution + end + + INSTANCE = create + def scope(association, connection) klass = association.klass reflection = association.reflection @@ -22,6 +44,30 @@ module ActiveRecord Arel::Nodes::InnerJoin end + def self.get_bind_values(owner, chain) + bvs = [] + chain.each_with_index do |reflection, i| + if reflection.source_macro == :belongs_to + foreign_key = reflection.foreign_key + else + foreign_key = reflection.active_record_primary_key + end + + if reflection == chain.last + bvs << owner[foreign_key] + + if reflection.type + bvs << owner.class.base_class.name + end + else + if reflection.type + bvs << chain[i + 1].klass.base_class.name + end + end + end + bvs + end + private def construct_tables(chain, klass, refl, alias_tracker) @@ -49,10 +95,7 @@ module ActiveRecord end def bind_value(scope, column, value, alias_tracker) - substitute = alias_tracker.connection.substitute_at( - column, scope.bind_values.length) - scope.bind_values += [[column, value]] - substitute + @bind_substitution.bind_value scope, column, value, alias_tracker end def bind(scope, table_name, column_name, value, tracker) diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 803e3ab9ab..b623f1375d 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -412,9 +412,23 @@ module ActiveRecord end private + def get_records + return scope.to_a if reflection.scope_chain.any?(&:any?) + + conn = klass.connection + sc = reflection.association_scope_cache(conn) do + StatementCache.create(conn) { |params| + as = AssociationScope.create { params.bind } + target_scope.merge as.scope(self, conn) + } + end + + binds = AssociationScope.get_bind_values(owner, reflection.chain) + sc.execute binds, klass, klass.connection + end def find_target - records = scope.to_a + records = get_records records.each { |record| set_inverse_instance(record) } records end |