diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index cf439b0dc0f20ae57bee87a8de9723201b2830eb..728dec8925df3162305396821efbf876cd9032bf 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -55,6 +55,7 @@ module ActiveRecord autoload :FinderMethods autoload :CalculationMethods autoload :PredicateBuilder + autoload :SpawnMethods end autoload :Base diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 9cfd9b6d23f9a24ff3ba47fa329fa7705a7a7f77..a4d11f813d2af313ad3fe0179962ba5137400187 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -1,6 +1,6 @@ module ActiveRecord class Relation - include QueryMethods, FinderMethods, CalculationMethods + include QueryMethods, FinderMethods, CalculationMethods, SpawnMethods delegate :length, :collect, :map, :each, :all?, :to => :to_a @@ -28,41 +28,6 @@ def create!(*args, &block) with_create_scope { @klass.create!(*args, &block) } end - def merge(r) - raise ArgumentError, "Cannot merge a #{r.klass.name} relation with #{@klass.name} relation" if r.klass != @klass - - merged_relation = spawn(table).eager_load(r.eager_load_associations).preload(r.preload_associations).includes(r.include_associations) - merged_relation.readonly = r.readonly - - [self.relation, r.relation].each do |arel| - merged_relation = merged_relation. - joins(arel.joins(arel)). - group(arel.groupings). - limit(arel.taken). - offset(arel.skipped). - select(arel.send(:select_clauses)). - from(arel.sources) - end - - relation_order = r.send(:order_clause) - merged_order = relation_order.present? ? relation_order : order_clause - merged_relation = merged_relation.order(merged_order) - - merged_wheres = @relation.wheres - - r.wheres.each do |w| - if w.is_a?(Arel::Predicates::Equality) - merged_wheres = merged_wheres.reject {|p| p.is_a?(Arel::Predicates::Equality) && p.operand1.name == w.operand1.name } - end - - merged_wheres << w - end - - merged_relation.where(*merged_wheres) - end - - alias :& :merge - def respond_to?(method, include_private = false) return true if @relation.respond_to?(method, include_private) || Array.method_defined?(method) @@ -164,16 +129,6 @@ def reset self end - def spawn(relation = @relation) - relation = Relation.new(@klass, relation) - relation.readonly = @readonly - relation.preload_associations = @preload_associations - relation.eager_load_associations = @eager_load_associations - relation.include_associations = @include_associations - relation.table = table - relation - end - def table @table ||= Arel::Table.new(@klass.table_name, Arel::Sql::Engine.new(@klass)) end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb new file mode 100644 index 0000000000000000000000000000000000000000..4a64f0c6a909d2457489577f6dc02a871249f884 --- /dev/null +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -0,0 +1,49 @@ +module ActiveRecord + module SpawnMethods + def spawn(relation = @relation) + relation = Relation.new(@klass, relation) + relation.readonly = @readonly + relation.preload_associations = @preload_associations + relation.eager_load_associations = @eager_load_associations + relation.include_associations = @include_associations + relation.table = table + relation + end + + def merge(r) + raise ArgumentError, "Cannot merge a #{r.klass.name} relation with #{@klass.name} relation" if r.klass != @klass + + merged_relation = spawn(table).eager_load(r.eager_load_associations).preload(r.preload_associations).includes(r.include_associations) + merged_relation.readonly = r.readonly + + [self.relation, r.relation].each do |arel| + merged_relation = merged_relation. + joins(arel.joins(arel)). + group(arel.groupings). + limit(arel.taken). + offset(arel.skipped). + select(arel.send(:select_clauses)). + from(arel.sources) + end + + relation_order = r.send(:order_clause) + merged_order = relation_order.present? ? relation_order : order_clause + merged_relation = merged_relation.order(merged_order) + + merged_wheres = @relation.wheres + + r.wheres.each do |w| + if w.is_a?(Arel::Predicates::Equality) + merged_wheres = merged_wheres.reject {|p| p.is_a?(Arel::Predicates::Equality) && p.operand1.name == w.operand1.name } + end + + merged_wheres << w + end + + merged_relation.where(*merged_wheres) + end + + alias :& :merge + + end +end