aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/active_relation/relations/aggregation.rb1
-rw-r--r--lib/active_relation/relations/alias.rb2
-rw-r--r--lib/active_relation/relations/join.rb21
-rw-r--r--lib/active_relation/relations/rename.rb4
-rw-r--r--lib/active_relation/relations/table.rb2
-rw-r--r--spec/active_relation/predicates/binary_spec.rb10
-rw-r--r--spec/active_relation/primitives/attribute_spec.rb8
-rw-r--r--spec/active_relation/relations/alias_spec.rb1
-rw-r--r--spec/active_relation/relations/join_spec.rb81
-rw-r--r--spec/active_relation/relations/rename_spec.rb35
-rw-r--r--spec/active_relation/relations/table_spec.rb9
11 files changed, 94 insertions, 80 deletions
diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb
index 9e803b3587..7910223673 100644
--- a/lib/active_relation/relations/aggregation.rb
+++ b/lib/active_relation/relations/aggregation.rb
@@ -21,7 +21,6 @@ module ActiveRelation
expressions.collect { |e| e.bind(self) }
end
- protected
def aggregation?
true
end
diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb
index 5b45d9dce4..941a95c58e 100644
--- a/lib/active_relation/relations/alias.rb
+++ b/lib/active_relation/relations/alias.rb
@@ -3,7 +3,7 @@ module ActiveRelation
attr_reader :alias
def aliased_prefix_for(attribute)
- @alias
+ self[attribute] and @alias
end
def initialize(relation, aliaz)
diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb
index 4c4f2e66a2..c61680fd55 100644
--- a/lib/active_relation/relations/join.rb
+++ b/lib/active_relation/relations/join.rb
@@ -20,20 +20,22 @@ module ActiveRelation
def attributes
[
- relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes,
- relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes,
+ relation1.attributes.collect(&:to_attribute),
+ relation2.attributes.collect(&:to_attribute),
].flatten.collect { |a| a.bind(self) }
end
def prefix_for(attribute)
- (relation1[attribute] && relation1.aliased_prefix_for(attribute)) ||
- (relation2[attribute] && relation2.aliased_prefix_for(attribute))
+ relation1.aliased_prefix_for(attribute) or
+ relation2.aliased_prefix_for(attribute)
end
alias_method :aliased_prefix_for, :prefix_for
protected
def joins
- [relation1.joins, relation2.joins, join].compact.join(" ")
+ right_table_sql = relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql)
+ this_join = [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ")
+ [relation1.joins, relation2.joins, this_join].compact.join(" ")
end
def selects
@@ -46,14 +48,5 @@ module ActiveRelation
def table_sql
relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql)
end
-
- private
- def join
- [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ")
- end
-
- def right_table_sql
- relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql)
- end
end
end \ No newline at end of file
diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb
index 6b1b29bf75..20e79ebefb 100644
--- a/lib/active_relation/relations/rename.rb
+++ b/lib/active_relation/relations/rename.rb
@@ -8,8 +8,8 @@ module ActiveRelation
end
def ==(other)
- self.class == other.class and
- relation == other.relation and
+ self.class == other.class and
+ relation == other.relation and
attribute == other.attribute and
pseudonym == other.pseudonym
end
diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb
index c8ccb22fdd..d85c268019 100644
--- a/lib/active_relation/relations/table.rb
+++ b/lib/active_relation/relations/table.rb
@@ -17,7 +17,7 @@ module ActiveRelation
end
def prefix_for(attribute)
- name
+ self[attribute] and name
end
alias_method :aliased_prefix_for, :prefix_for
diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb
index 599cfa2942..127375f24c 100644
--- a/spec/active_relation/predicates/binary_spec.rb
+++ b/spec/active_relation/predicates/binary_spec.rb
@@ -3,10 +3,10 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
module ActiveRelation
describe Binary do
before do
- @relation1 = Table.new(:foo)
- @relation2 = Table.new(:bar)
- @attribute1 = Attribute.new(@relation1, :name1)
- @attribute2 = Attribute.new(@relation2, :name2)
+ @relation1 = Table.new(:users)
+ @relation2 = Table.new(:photos)
+ @attribute1 = @relation1[:id]
+ @attribute2 = @relation2[:id]
class ConcreteBinary < Binary
def predicate_sql
"<=>"
@@ -43,7 +43,7 @@ module ActiveRelation
describe '#to_sql' do
it 'manufactures correct sql' do
ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like("""
- `foo`.`name1` <=> `bar`.`name2`
+ `users`.`id` <=> `photos`.`id`
""")
end
end
diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb
index 39feacbac7..a931ea2150 100644
--- a/spec/active_relation/primitives/attribute_spec.rb
+++ b/spec/active_relation/primitives/attribute_spec.rb
@@ -62,12 +62,16 @@ module ActiveRelation
describe '#to_sql' do
describe Sql::Strategy do
+ before do
+ stub(@relation).prefix_for(anything) { 'bruisers' }
+ end
+
it "manufactures sql without an alias if the strategy is Predicate" do
- Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`users`.`name`")
+ Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`bruisers`.`name`")
end
it "manufactures sql with an alias if the strategy is Projection" do
- Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`users`.`name` AS 'alias'")
+ Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`bruisers`.`name` AS 'alias'")
end
end
end
diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb
index ddb0c59d08..a2deae2840 100644
--- a/spec/active_relation/relations/alias_spec.rb
+++ b/spec/active_relation/relations/alias_spec.rb
@@ -16,6 +16,7 @@ module ActiveRelation
describe '#aliased_prefix_for' do
it "returns the alias" do
@alias_relation.aliased_prefix_for(@relation[:id]).should == :foo
+ @alias_relation.aliased_prefix_for(:does_not_exist).should be_nil
end
end
end
diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb
index b131ac6918..b60238fa7e 100644
--- a/spec/active_relation/relations/join_spec.rb
+++ b/spec/active_relation/relations/join_spec.rb
@@ -5,13 +5,19 @@ module ActiveRelation
before do
@relation1 = Table.new(:users)
@relation2 = Table.new(:photos)
- @predicate = Equality.new(@relation1[:id], @relation2[:id])
+ @predicate = @relation1[:id].equals(@relation2[:user_id])
end
describe '==' do
+ before do
+ @another_predicate = @relation1[:id].equals(1)
+ @another_relation = Table.new(:cameras)
+ end
+
it 'obtains if the two relations and the predicate are identical' do
Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate)
- Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation1, @predicate)
+ Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @another_relation, @predicate)
+ Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation2, @another_predicate)
end
it 'is commutative on the relations' do
@@ -26,22 +32,6 @@ module ActiveRelation
end
end
- describe '#attributes' do
- describe 'with simple relations' do
- before do
- @join = Join.new("INNER JOIN", @relation1, @relation2, @predicate)
- end
-
- it 'combines the attributes of the two relations' do
- @join.attributes.should ==
- (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(@join) }
- end
-
- it 'does something peculiar with expressions when aggregate' do
- pending
- end
- end
- end
describe '#prefix_for' do
it 'needs a test' do
@@ -49,13 +39,21 @@ module ActiveRelation
end
end
- describe '#to_sql' do
- describe 'with simple relations' do
+ describe 'with simple relations' do
+ describe '#attributes' do
+ it 'combines the attributes of the two relations' do
+ simple_join = Join.new("INNER JOIN", @relation1, @relation2, @predicate)
+ simple_join.attributes.should ==
+ (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(simple_join) }
+ end
+ end
+
+ describe '#to_sql' 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 `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
FROM `users`
- INNER JOIN `photos` ON `users`.`id` = `photos`.`id`
+ INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id`
""")
end
@@ -64,49 +62,60 @@ module ActiveRelation
@relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like("""
SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
FROM `users`
- INNER JOIN `photos` ON `users`.`id` = `photos`.`id`
+ INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id`
WHERE `users`.`id` = 1
AND `photos`.`id` = 2
""")
end
end
-
- describe 'aggregated relations' do
- before do
- @relation = Table.new(:users)
- photos = Table.new(:photos)
- @aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]).rename(photos[:id].count, :cnt).as(:photo_count)
- @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id])
+ end
+
+ describe 'with aggregated relations' do
+ before do
+ @aggregation = @relation2 \
+ .aggregate(@relation2[:user_id], @relation2[:id].count) \
+ .group(@relation2[:user_id]) \
+ .rename(@relation2[:id].count, :cnt) \
+ .as(:photo_count)
+ end
+
+ describe '#attributes' do
+ it 'it transforms aggregate expressions into attributes' do
+ join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate)
+ join_with_aggregation.attributes.should ==
+ (@relation1.attributes + @aggregation.attributes).collect(&:to_attribute).collect { |a| a.bind(join_with_aggregation) }
end
-
+ end
+
+ describe '#to_sql' do
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("""
+ Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like("""
SELECT `users`.`id`, `users`.`name`, `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`
+ ON `users`.`id` = `photo_count`.`user_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("""
+ Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like("""
SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`id`, `users`.`name`
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`
+ ON `users`.`id` = `photo_count`.`user_id`
""")
end
end
it "keeps selects on the aggregation within the derived table" do
- Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like("""
+ Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].equals(1)), @predicate).to_sql.should be_like("""
SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt`
FROM `users`
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`
+ ON `users`.`id` = `photo_count`.`user_id`
""")
end
end
diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb
index 339bb2f39f..deb538615b 100644
--- a/spec/active_relation/relations/rename_spec.rb
+++ b/spec/active_relation/relations/rename_spec.rb
@@ -3,44 +3,51 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
module ActiveRelation
describe Rename do
before do
- @relation1 = Table.new(:users)
- @relation2 = Table.new(:photos)
- @renamed_relation = Rename.new(@relation1, @relation1[:id] => :schmid)
+ @relation = Table.new(:users)
end
describe '#initialize' do
it "manufactures nested rename relations if multiple renames are provided" do
- Rename.new(@relation1, @relation1[:id] => :humpty, @relation1[:name] => :dumpty). \
- should == Rename.new(Rename.new(@relation1, @relation1[:name] => :dumpty), @relation1[:id] => :humpty)
+ Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \
+ should == Rename.new(Rename.new(@relation, @relation[:name] => :dumpty), @relation[:id] => :humpty)
end
end
describe '==' do
+ before do
+ @another_relation = Table.new(:photos)
+ end
+
it "obtains if the relation, attribute, and rename are identical" do
- Rename.new(@relation1, @relation1[:id] => :humpty).should == Rename.new(@relation1, @relation1[:id] => :humpty)
- Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation1, @relation1[:id] => :dumpty)
- Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation2, @relation2[:id] => :humpty)
+ Rename.new(@relation, @relation[:id] => :humpty).should == Rename.new(@relation, @relation[:id] => :humpty)
+ Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@relation, @relation[:id] => :dumpty)
+ Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@another_relation, @relation[:id] => :humpty)
end
end
describe '#attributes' do
+ before do
+ @renamed_relation = Rename.new(@relation, @relation[:id] => :schmid)
+ end
+
it "manufactures a list of attributes with the renamed attribute renameed" do
- @renamed_relation.attributes.should include(@renamed_relation[:schmid])
- @renamed_relation.should have(@relation1.attributes.size).attributes
- pending "this should be more rigorous"
+ @renamed_relation.attributes.should include(@relation[:id].as(:schmid).bind(@renamed_relation))
+ @renamed_relation.attributes.should_not include(@relation[:id].bind(@renamed_relation))
+ @renamed_relation.attributes.should include(@relation[:name].bind(@renamed_relation))
+ @renamed_relation.should have(@relation.attributes.size).attributes
end
end
describe '#qualify' do
it "distributes over the relation and renames" do
- Rename.new(@relation1, @relation1[:id] => :schmid).qualify. \
- should == Rename.new(@relation1.qualify, @relation1[:id].qualify => :schmid)
+ Rename.new(@relation, @relation[:id] => :schmid).qualify. \
+ should == Rename.new(@relation.qualify, @relation[:id].qualify => :schmid)
end
end
describe '#to_sql' do
it 'manufactures sql renaming the attribute' do
- @renamed_relation.to_sql.should be_like("""
+ Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like("""
SELECT `users`.`id` AS 'schmid', `users`.`name`
FROM `users`
""")
diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb
index 498d841040..13a9198447 100644
--- a/spec/active_relation/relations/table_spec.rb
+++ b/spec/active_relation/relations/table_spec.rb
@@ -27,7 +27,7 @@ module ActiveRelation
describe 'when given an', Expression do
before do
- @expression = Expression.new(Attribute.new(@relation, :id), "COUNT")
+ @expression = @relation[:id].count
end
it "returns the Expression if the Expression is within the relation" do
@@ -46,14 +46,15 @@ module ActiveRelation
end
describe '#prefix_for' do
- it "returns the table name" do
- @relation.prefix_for(Attribute.new(@relation, :id)).should == :users
+ it "returns the table name if the relation contains the attribute" do
+ @relation.prefix_for(@relation[:id]).should == :users
+ @relation.prefix_for(:does_not_exist).should be_nil
end
end
describe '#aliased_prefix_for' do
it "returns the table name" do
- @relation.aliased_prefix_for(Attribute.new(@relation, :id)).should == :users
+ @relation.aliased_prefix_for(@relation[:id]).should == :users
end
end