aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Kallen <nkallen@nick-kallens-computer-2.local>2008-01-21 20:02:48 -0800
committerNick Kallen <nkallen@nick-kallens-computer-2.local>2008-01-21 20:02:48 -0800
commit7f35d492372fd91cd35e7f9a2408efd64d28ccf5 (patch)
tree569b2217f861f99fa32104c7c9cc00ec09e50830
parent559d9bbfe09034e807e5eae169bea26df780aa36 (diff)
downloadrails-7f35d492372fd91cd35e7f9a2408efd64d28ccf5.tar.gz
rails-7f35d492372fd91cd35e7f9a2408efd64d28ccf5.tar.bz2
rails-7f35d492372fd91cd35e7f9a2408efd64d28ccf5.zip
joining on aggregations; this time where the aggregation is on the right.
-rw-r--r--lib/active_relation/relations/alias.rb4
-rw-r--r--lib/active_relation/relations/compound.rb3
-rw-r--r--lib/active_relation/relations/join.rb28
-rw-r--r--lib/active_relation/relations/relation.rb4
-rw-r--r--lib/active_relation/relations/rename.rb6
-rw-r--r--spec/active_relation/relations/join_spec.rb50
6 files changed, 66 insertions, 29 deletions
diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb
index 701ab189d0..26b582e98a 100644
--- a/lib/active_relation/relations/alias.rb
+++ b/lib/active_relation/relations/alias.rb
@@ -8,11 +8,11 @@ module ActiveRelation
end
def attributes
- relation.attributes.collect { |attribute| attribute.substitute(self) }
+ relation.attributes.collect { |a| a.substitute(self) }
end
def ==(other)
- relation == other.relation and self.alias == other.alias
+ relation == other.relation and @alias == other.alias
end
protected
diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb
index a7595c9e3d..d71d0ffeb5 100644
--- a/lib/active_relation/relations/compound.rb
+++ b/lib/active_relation/relations/compound.rb
@@ -2,7 +2,8 @@ module ActiveRelation
class Compound < Relation
attr_reader :relation
- delegate :projections, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?,
+ delegate :projections, :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit,
+ :offset, :name, :alias, :aggregation?,
:to => :relation
end
end \ No newline at end of file
diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb
index d4cfe19239..37ed558e9f 100644
--- a/lib/active_relation/relations/join.rb
+++ b/lib/active_relation/relations/join.rb
@@ -1,7 +1,6 @@
module ActiveRelation
class Join < Relation
attr_reader :join_sql, :relation1, :relation2, :predicates
- delegate :table_sql, :to => :relation1
def initialize(join_sql, relation1, relation2, *predicates)
@join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates
@@ -16,6 +15,10 @@ module ActiveRelation
def qualify
Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify))
end
+
+ def attributes
+ projections.map(&:to_attribute)
+ end
protected
def joins
@@ -23,28 +26,33 @@ module ActiveRelation
end
def selects
- relation1.send(:selects) + relation2.send(:selects)
+ [
+ (relation1.send(:selects) unless relation1.aggregation?),
+ (relation2.send(:selects) unless relation2.aggregation?)
+ ].compact.flatten
end
- # this is magick!!!
def projections
- relation1.send(:projections) + relation2.attributes
+ [
+ relation1.aggregation?? relation1.attributes : relation1.send(:projections),
+ relation2.aggregation?? relation2.attributes : relation2.send(:projections),
+ ].flatten
end
def attribute(name)
relation1[name] || relation2[name]
end
-
- private
- def join
- "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}"
+
+ def table_sql
+ relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql)
end
+ private
def join
- [join_sql, right_table, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ")
+ [join_sql, right_table_sql, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ")
end
- def right_table
+ def right_table_sql
relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql)
end
end
diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb
index cb981eb3de..d09ee058ef 100644
--- a/lib/active_relation/relations/relation.rb
+++ b/lib/active_relation/relations/relation.rb
@@ -77,10 +77,6 @@ module ActiveRelation
end
include Operations
- def attributes
- projections.collect(&:to_attribute)
- end
-
def aggregation?
false
end
diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb
index c9c47f95b8..94e5edcd47 100644
--- a/lib/active_relation/relations/rename.rb
+++ b/lib/active_relation/relations/rename.rb
@@ -14,7 +14,11 @@ module ActiveRelation
def qualify
Rename.new(relation.qualify, autonym.qualify => self.pseudonym)
end
-
+
+ def attributes
+ projections.collect(&:to_attribute)
+ end
+
protected
def projections
relation.send(:projections).collect(&method(:substitute))
diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb
index 00a6218c03..422a93772d 100644
--- a/spec/active_relation/relations/join_spec.rb
+++ b/spec/active_relation/relations/join_spec.rb
@@ -42,22 +42,27 @@ module ActiveRelation
describe '#to_sql' do
describe 'with simple relations' do
- before do
- @relation1 = @relation1.select(@relation1[:id].equals(1))
- end
-
- it 'manufactures sql joining the two tables on the predicate, merging the selects' do
+ it 'manufactures sql joining the two tables on the predicate' do
Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like("""
SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id`
FROM `foo`
INNER JOIN `bar` ON `foo`.`id` = `bar`.`id`
- WHERE
- `foo`.`id` = 1
""")
end
+
+ it 'manufactures sql joining the two tables, merging any selects' do
+ Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)),
+ @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like("""
+ SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id`
+ FROM `foo`
+ INNER JOIN `bar` ON `foo`.`id` = `bar`.`id`
+ WHERE `foo`.`id` = 1
+ AND `bar`.`id` = 2
+ """)
+ end
end
- describe 'with aggregated relations' do
+ describe 'aggregated relations' do
before do
@relation = Table.new(:users)
photos = Table.new(:photos)
@@ -66,11 +71,34 @@ module ActiveRelation
@predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id])
end
- it 'manufactures sql joining the left table to a derived table' do
- Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like("""
+ describe 'with the aggregation on the right' do
+ it 'manufactures sql joining the left table to a derived table' do
+ Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like("""
+ SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt`
+ FROM `users`
+ INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count`
+ ON `photo_count`.`user_id` = `users`.`id`
+ """)
+ end
+ end
+
+ describe 'with the aggregation on the left' do
+ it 'manufactures sql joining the right table to a derived table' do
+ Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like("""
+ SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id`
+ FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count`
+ INNER JOIN `users`
+ ON `photo_count`.`user_id` = `users`.`id`
+ """)
+ end
+ end
+
+ it "keeps selects on the aggregation within the derived table" do
+ pending
+ Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like("""
SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt`
FROM `users`
- INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count`
+ INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count`
ON `photo_count`.`user_id` = `users`.`id`
""")
end