diff options
author | Jon Leighton <j@jonathanleighton.com> | 2012-04-12 16:29:18 +0100 |
---|---|---|
committer | Jon Leighton <j@jonathanleighton.com> | 2012-04-13 13:17:42 +0100 |
commit | 3b863366947c063e19bac1504274ef22831e37d9 (patch) | |
tree | 03397a6f0acdcc197f49166c7799b49e0749d105 /activerecord/lib/active_record/relation/merger.rb | |
parent | 4e3e5138b537e999b5bdf6fbb1243890123ada5d (diff) | |
download | rails-3b863366947c063e19bac1504274ef22831e37d9.tar.gz rails-3b863366947c063e19bac1504274ef22831e37d9.tar.bz2 rails-3b863366947c063e19bac1504274ef22831e37d9.zip |
Extract clusterfuck method for surgery
Diffstat (limited to 'activerecord/lib/active_record/relation/merger.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/merger.rb | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb new file mode 100644 index 0000000000..2f50b9a492 --- /dev/null +++ b/activerecord/lib/active_record/relation/merger.rb @@ -0,0 +1,84 @@ +module ActiveRecord + class Relation + class Merger + attr_reader :relation, :other + + def initialize(relation, other) + @relation = relation + + if other.default_scoped? && other.klass != relation.klass + @other = other.with_default_scope + else + @other = other + end + end + + def merge + Relation::ASSOCIATION_METHODS.each do |method| + value = other.send(:"#{method}_values") + + unless value.empty? + relation.send("#{method}!", value) + end + end + + (Relation::MULTI_VALUE_METHODS - [:joins, :where, :order, :binds]).each do |method| + value = other.send(:"#{method}_values") + next if value.empty? + + value += relation.send(:"#{method}_values") + relation.send :"#{method}_values=", value + end + + relation.joins_values += other.joins_values + + merged_wheres = relation.where_values + other.where_values + + merged_binds = (relation.bind_values + other.bind_values).uniq(&:first) + + 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 + + relation.where_values = merged_wheres + relation.bind_values = merged_binds + + (Relation::SINGLE_VALUE_METHODS - [:lock, :create_with, :reordering]).each do |method| + value = other.send(:"#{method}_value") + relation.send(:"#{method}_value=", value) unless value.nil? + end + + relation.lock_value = other.lock_value unless relation.lock_value + + unless other.create_with_value.empty? + relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value) + end + + if other.reordering_value + # override any order specified in the original relation + relation.reordering_value = true + relation.order_values = other.order_values + else + # merge in order_values from r + relation.order_values += other.order_values + end + + # Apply scope extension modules + relation.send :apply_modules, other.extensions + + relation + end + end + end +end |