diff options
author | Jon Leighton <j@jonathanleighton.com> | 2012-04-13 12:10:51 +0100 |
---|---|---|
committer | Jon Leighton <j@jonathanleighton.com> | 2012-04-13 13:17:42 +0100 |
commit | 0183193a6aecefb3b55a5abf20792aee6b57dcc1 (patch) | |
tree | 4afa50fa7df611e9119209da0930095e19996617 /activerecord/lib/active_record | |
parent | e4f0fbd994ab0c333e615be68a8d40593c7058e3 (diff) | |
download | rails-0183193a6aecefb3b55a5abf20792aee6b57dcc1.tar.gz rails-0183193a6aecefb3b55a5abf20792aee6b57dcc1.tar.bz2 rails-0183193a6aecefb3b55a5abf20792aee6b57dcc1.zip |
Allow Relation#merge to take a hash
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation/merger.rb | 113 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation/spawn_methods.rb | 7 |
3 files changed, 75 insertions, 47 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 0d7da67c98..88fb0e9dda 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -11,7 +11,7 @@ module ActiveRecord :order, :joins, :where, :having, :bind, :references] SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering, - :reverse_order, :uniq] + :reverse_order, :uniq, :create_with] include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 86e7f3ae0f..23629eedf6 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -14,6 +14,40 @@ module ActiveRecord end def merge + HashMerger.new(relation, other_hash).merge + end + + private + + def other_hash + hash = {} + Relation::MULTI_VALUE_METHODS.map { |name| hash[name] = other.send("#{name}_values") } + Relation::SINGLE_VALUE_METHODS.map { |name| hash[name] = other.send("#{name}_value") } + hash[:extensions] = other.extensions + hash + end + end + + class HashMerger + attr_reader :relation, :values + + def initialize(relation, values) + @relation = relation + @values = values + end + + def normal_values + Relation::SINGLE_VALUE_METHODS + + Relation::MULTI_VALUE_METHODS - + [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering] + end + + def merge + normal_values.each do |name| + value = values[name] + relation.send("#{name}!", value) unless value.blank? + end + merge_multi_values merge_single_values @@ -23,70 +57,61 @@ module ActiveRecord private def merge_multi_values - values = Relation::MULTI_VALUE_METHODS - [:where, :order, :bind] - - values.each do |method| - value = other.send(:"#{method}_values") - - unless value.empty? - relation.send("#{method}!", value) - end - end - relation.where_values = merged_wheres relation.bind_values = merged_binds - if other.reordering_value + if values[:reordering] # override any order specified in the original relation - relation.reorder! other.order_values - else + relation.reorder! values[:order] + elsif values[:order] # merge in order_values from r - relation.order_values += other.order_values + relation.order_values += values[:order] end # Apply scope extension modules - relation.send :apply_modules, other.extensions + relation.send :apply_modules, values[:extensions] if values[:extensions] end def merge_single_values - values = Relation::SINGLE_VALUE_METHODS - [:reverse_order, :lock, :create_with, :reordering] + relation.lock_value = values[:lock] unless relation.lock_value + relation.reverse_order_value = values[:reverse_order] - values.each do |method| - value = other.send(:"#{method}_value") - relation.send("#{method}!", value) if value - end - - relation.lock_value = other.lock_value unless relation.lock_value - relation.reverse_order_value = other.reverse_order_value - - unless other.create_with_value.empty? - relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value) + unless values[:create_with].blank? + relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with]) end end def merged_binds - (relation.bind_values + other.bind_values).uniq(&:first) + if values[:bind] + (relation.bind_values + values[:bind]).uniq(&:first) + else + relation.bind_values + end end def merged_wheres - merged_wheres = relation.where_values + other.where_values - - unless relation.where_values.empty? - # Remove duplicates, last one wins. - seen = Hash.new { |h,table| h[table] = {} } - merged_wheres = merged_wheres.reverse.reject { |w| - nuke = false - if w.respond_to?(:operator) && w.operator == :== - name = w.left.name - table = w.left.relation.name - nuke = seen[table][name] - seen[table][name] = true - end - nuke - }.reverse - end + if values[:where] + merged_wheres = relation.where_values + values[:where] + + unless relation.where_values.empty? + # Remove duplicates, last one wins. + seen = Hash.new { |h,table| h[table] = {} } + merged_wheres = merged_wheres.reverse.reject { |w| + nuke = false + if w.respond_to?(:operator) && w.operator == :== + name = w.left.name + table = w.left.relation.name + nuke = seen[table][name] + seen[table][name] = true + end + nuke + }.reverse + end - merged_wheres + merged_wheres + else + relation.where_values + end end end end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 80c129d361..40af665769 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -5,10 +5,13 @@ module ActiveRecord module SpawnMethods def merge(other) if other - if other.is_a?(Array) + case other + when Array to_a & other + when Hash + Relation::HashMerger.new(clone, other).merge else - ActiveRecord::Relation::Merger.new(clone, other).merge + Relation::Merger.new(clone, other).merge end else self |