Browse files

Merge branch 'master' of github.com:rails/rails

  • Loading branch information...
2 parents 95762cb + a0ff5f8 commit 9521fcbcc295cb1dd34f7d458c40790466a55244 @dhh dhh committed Dec 27, 2009
Showing with 58 additions and 24 deletions.
  1. +26 −17 activerecord/lib/active_record/relation.rb
  2. +32 −7 activerecord/test/cases/relations_test.rb
View
43 activerecord/lib/active_record/relation.rb
@@ -1,8 +1,8 @@
module ActiveRecord
class Relation
delegate :to_sql, :to => :relation
- delegate :length, :collect, :find, :map, :each, :to => :to_a
- attr_reader :relation, :klass
+ delegate :length, :collect, :map, :each, :to => :to_a
+ attr_reader :relation, :klass, :associations_to_preload, :eager_load_associations
def initialize(klass, relation, readonly = false, preload = [], eager_load = [])
@klass, @relation = klass, relation
@@ -12,6 +12,21 @@ def initialize(klass, relation, readonly = false, preload = [], eager_load = [])
@loaded = false
end
+ def merge(r)
+ joins(r.relation.joins(r.relation)).
+ group(r.send(:group_clauses).join(', ')).
+ order(r.send(:order_clauses).join(', ')).
+ where(r.send(:where_clause)).
+ limit(r.taken).
+ offset(r.skipped).
+ select(r.send(:select_clauses).join(', ')).
+ eager_load(r.eager_load_associations).
+ preload(r.associations_to_preload).
+ from(r.send(:sources).any? ? r.send(:from_clauses) : nil)
+ end
+
+ alias :& :merge
+
def preload(*associations)
create_new_relation(@relation, @readonly, @associations_to_preload + Array.wrap(associations))
end
@@ -25,23 +40,19 @@ def readonly
end
def select(selects)
- create_new_relation(@relation.project(selects))
+ selects.present? ? create_new_relation(@relation.project(selects)) : create_new_relation
end
- # TODO : This is temporary. We need .from in Arel.
- attr_writer :from
def from(from)
- relation = create_new_relation
- relation.from = from
- relation
+ from.present? ? create_new_relation(@relation.from(from)) : create_new_relation
end
def group(groups)
- create_new_relation(@relation.group(groups))
+ groups.present? ? create_new_relation(@relation.group(groups)) : create_new_relation
end
def order(orders)
- create_new_relation(@relation.order(orders))
+ orders.present? ? create_new_relation(@relation.order(orders)) : create_new_relation
end
def reverse_order
@@ -57,19 +68,19 @@ def reverse_order
end
def limit(limits)
- create_new_relation(@relation.take(limits))
+ limits.present? ? create_new_relation(@relation.take(limits)) : create_new_relation
end
def offset(offsets)
- create_new_relation(@relation.skip(offsets))
+ offsets.present? ? create_new_relation(@relation.skip(offsets)) : create_new_relation
end
def on(join)
create_new_relation(@relation.on(join))
end
def joins(join, join_type = nil)
- return self if join.blank?
+ return create_new_relation if join.blank?
join_relation = case join
when String
@@ -116,7 +127,7 @@ def to_a
:conditions => where_clause,
:limit => @relation.taken,
:offset => @relation.skipped,
- :from => @from
+ :from => (@relation.send(:from_clauses) if @relation.send(:sources).any?)
},
ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, @eager_load_associations, nil))
end
@@ -289,9 +300,7 @@ def find_some(ids)
end
def create_new_relation(relation = @relation, readonly = @readonly, preload = @associations_to_preload, eager_load = @eager_load_associations)
- r = self.class.new(@klass, relation, readonly, preload, eager_load)
- r.from = @from
- r
+ self.class.new(@klass, relation, readonly, preload, eager_load)
end
def where_clause(join_string = "\n\tAND ")
View
39 activerecord/test/cases/relations_test.rb
@@ -38,7 +38,7 @@ def test_loaded_all
end
def test_scoped_first
- topics = Topic.scoped
+ topics = Topic.scoped.order('id ASC')
assert_queries(1) do
2.times { assert_equal "The First Topic", topics.first.title }
@@ -48,7 +48,7 @@ def test_scoped_first
end
def test_loaded_first
- topics = Topic.scoped
+ topics = Topic.scoped.order('id ASC')
assert_queries(1) do
topics.all # force load
@@ -244,7 +244,7 @@ def test_dynamic_find_by_attributes_bang
author = Author.scoped.find_by_id!(authors(:david).id)
assert_equal "David", author.name
- assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!('invalid', 'wt') }
+ assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!(20, 'invalid') }
end
def test_dynamic_find_all_by_attributes
@@ -281,7 +281,7 @@ def test_find_id
david = authors.find(authors(:david).id)
assert_equal 'David', david.name
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('invalid') }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') }
end
def test_find_ids
@@ -294,16 +294,17 @@ def test_find_ids
assert_equal 'Mary', results[1].name
assert_equal results, authors.find([authors(:david).id, authors(:mary).id])
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, 'invalid') }
- assert_raises(ActiveRecord::RecordNotFound) { authors.find(['invalid', 'oops']) }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, '42') }
+ assert_raises(ActiveRecord::RecordNotFound) { authors.find(['42', 43]) }
end
def test_exists
davids = Author.where(:name => 'David')
assert davids.exists?
assert davids.exists?(authors(:david).id)
assert ! davids.exists?(authors(:mary).id)
- assert ! davids.exists?("hax'id")
+ assert ! davids.exists?("42")
+ assert ! davids.exists?(42)
fake = Author.where(:name => 'fake author')
assert ! fake.exists?
@@ -328,4 +329,28 @@ def test_destroy_all
assert davids.loaded?
end
+ def test_relation_merging
+ devs = Developer.where("salary >= 80000") & Developer.limit(2) & Developer.order('id ASC').where("id < 3")
+ assert_equal [developers(:david), developers(:jamis)], devs.to_a
+
+ dev_with_count = Developer.limit(1) & Developer.order('id DESC') & Developer.select('developers.*')
+ assert_equal [developers(:poor_jamis)], dev_with_count.to_a
+ end
+
+ def test_relation_merging_with_eager_load
+ relations = []
+ relations << (Post.order('comments.id DESC') & Post.eager_load(:last_comment) & Post.scoped)
+ relations << (Post.eager_load(:last_comment) & Post.order('comments.id DESC') & Post.scoped)
+
+ relations.each do |posts|
+ post = posts.find { |p| p.id == 1 }
+ assert_equal Post.find(1).last_comment, post.last_comment
+ end
+ end
+
+ def test_relation_merging_with_preload
+ [Post.scoped & Post.preload(:author), Post.preload(:author) & Post.scoped].each do |posts|
+ assert_queries(2) { assert posts.first.author }
+ end
+ end
end

0 comments on commit 9521fcb

Please sign in to comment.