diff options
author | eileencodes <eileencodes@gmail.com> | 2014-11-24 14:07:52 -0500 |
---|---|---|
committer | eileencodes <eileencodes@gmail.com> | 2015-01-02 17:15:31 -0500 |
commit | 4d27d56c3547e57bc509980eb6a9b14c39488c46 (patch) | |
tree | fcb2232477d13e0d36d48c5ad24b5c301d20d3f3 /activerecord/lib/active_record | |
parent | 17f6ca1e8a69f08a14fd7ab23dfe63691cd976a7 (diff) | |
download | rails-4d27d56c3547e57bc509980eb6a9b14c39488c46.tar.gz rails-4d27d56c3547e57bc509980eb6a9b14c39488c46.tar.bz2 rails-4d27d56c3547e57bc509980eb6a9b14c39488c46.zip |
Refactor `#get_chain` iteration to a linked list
The linked list lets us use a loop in `#add_constraints` and completely
remove the need for indexing the iteration becasue we have access to the
next item in the chain.
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 5268fb2ac8..cc6d23e80a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -33,11 +33,11 @@ module ActiveRecord reflection = association.reflection scope = klass.unscoped owner = association.owner - alias_tracker = AliasTracker.empty connection - chain = get_chain(reflection, association, alias_tracker) + alias_tracker = AliasTracker.create connection, association.klass.table_name + chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) - add_constraints(scope, owner, klass, reflection, alias_tracker, chain) + add_constraints(scope, owner, klass, reflection, alias_tracker, chain_head, chain_tail) end def join_type @@ -114,6 +114,8 @@ module ActiveRecord end class RuntimeReflection + attr_accessor :next + def initialize(reflection, association) @reflection = reflection @association = association @@ -161,6 +163,8 @@ module ActiveRecord end class ReflectionProxy < SimpleDelegator + attr_accessor :next + def alias_name(name, alias_tracker) @alias ||= begin alias_name = "#{plural_name}_#{name}" @@ -173,26 +177,28 @@ module ActiveRecord name = refl.name runtime_reflection = RuntimeReflection.new(refl, association) runtime_reflection.alias_name(name, tracker) - chain = [runtime_reflection] - chain.concat refl.chain.drop(1).map { |reflection| + prev = runtime_reflection + refl.chain.drop(1).each { |reflection| proxy = ReflectionProxy.new(reflection) proxy.alias_name(name, tracker) - proxy + prev.next = proxy + prev = proxy } - chain + [runtime_reflection, prev] end - def add_constraints(scope, owner, assoc_klass, refl, tracker, chain) - owner_reflection = chain.last + def add_constraints(scope, owner, assoc_klass, refl, tracker, chain_head, chain_tail) + owner_reflection = chain_tail table = owner_reflection.alias_name(refl.name, tracker) scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass) - # chain.first always == refl - chain.each_with_index do |reflection, i| + reflection = chain_head + loop do + break unless reflection table = reflection.alias_name(refl.name, tracker) - unless reflection == chain.last - next_reflection = chain[i + 1] + unless reflection == chain_tail + next_reflection = reflection.next foreign_table = next_reflection.alias_name(refl.name, tracker) scope = next_chain_scope(scope, table, reflection, tracker, assoc_klass, foreign_table, next_reflection) end @@ -206,7 +212,7 @@ module ActiveRecord scope.merge! item.except(:where, :includes, :bind) end - if reflection == chain.first + if reflection == chain_head scope.includes! item.includes_values end @@ -214,6 +220,7 @@ module ActiveRecord scope.bind_values += item.bind_values scope.order_values |= item.order_values end + reflection = reflection.next end scope |