diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb new file mode 100644 index 0000000000..02c72ef96d --- /dev/null +++ b/spec/active_relation/predicates/binary_spec.rb @@ -0,0 +1,42 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::Binary do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) + class ActiveRelation::Predicates::ConcreteBinary < ActiveRelation::Predicates::Binary + def predicate_sql + "<=>" + end + end + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2) + end + end + + describe '#qualify' do + it "distributes over the predicates and attributes" do + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + should == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) + end + end + + describe '#to_sql' do + it 'manufactures correct sql' do + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" + `foo`.`name1` <=> `bar`.`name2` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/predicates/equality_spec.rb new file mode 100644 index 0000000000..b3c7b597a0 --- /dev/null +++ b/spec/active_relation/predicates/equality_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::Equality do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/match_spec.rb b/spec/active_relation/predicates/match_spec.rb new file mode 100644 index 0000000000..a01f4fb76b --- /dev/null +++ b/spec/active_relation/predicates/match_spec.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::RelationInclusion do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute = @relation1[:baz] + end + + describe ActiveRelation::Predicates::RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/relation_inclusion_spec.rb b/spec/active_relation/predicates/relation_inclusion_spec.rb new file mode 100644 index 0000000000..de3dcf7747 --- /dev/null +++ b/spec/active_relation/predicates/relation_inclusion_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::RelationInclusion do + before do + foo = ActiveRelation::Relations::Table.new(:foo) + @relation1 = foo.project(foo[:id]) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute = @relation1[:id] + end + + describe ActiveRelation::Predicates::RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + end + end + + describe ActiveRelation::Predicates::RelationInclusion, '#to_sql' do + it "manufactures subselect sql" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(""" + `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/base_spec.rb b/spec/active_relation/relations/base_spec.rb new file mode 100644 index 0000000000..689e3ecadb --- /dev/null +++ b/spec/active_relation/relations/base_spec.rb @@ -0,0 +1,96 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Base do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :id) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + end + + describe '[]' do + it "manufactures an attribute when given a symbol" do + @relation1[:id].should == ActiveRelation::Primitives::Attribute.new(@relation1, :id) + end + + it "manufactures a range relation when given a range" do + @relation1[1..2].should == ActiveRelation::Relations::Range.new(@relation1, 1..2) + end + end + + describe '#include?' do + it "manufactures an inclusion predicate" do + @relation1.include?(@attribute1).should be_kind_of(ActiveRelation::Predicates::RelationInclusion) + end + end + + describe 'read operations' do + describe 'joins' do + before do + @predicate = @relation1[:id].equals(@relation2[:id]) + end + + describe '#join' do + it "manufactures an inner join operation between those two relations" do + @relation1.join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation1.outer_join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) + end + end + end + + describe '#project' do + it "collapses identical projections" do + pending + end + + it "manufactures a projection relation" do + @relation1.project(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Projection) + end + end + + describe '#rename' do + it "manufactures a rename relation" do + @relation1.rename(@attribute1, :foo).should be_kind_of(ActiveRelation::Relations::Rename) + end + end + + describe '#select' do + before do + @predicate = ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + end + + it "manufactures a selection relation" do + @relation1.select(@predicate).should be_kind_of(ActiveRelation::Relations::Selection) + end + + it "accepts arbitrary strings" do + @relation1.select("arbitrary").should be_kind_of(ActiveRelation::Relations::Selection) + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation1.order(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Order) + end + end + end + + describe 'write operations' do + describe '#delete' do + it 'manufactures a deletion relation' do + @relation1.delete.should be_kind_of(ActiveRelation::Relations::Deletion) + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + @relation1.insert(record = {:id => 1}).should be_kind_of(ActiveRelation::Relations::Insertion) + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/deletion_spec.rb b/spec/active_relation/relations/deletion_spec.rb new file mode 100644 index 0000000000..ed201ac0d9 --- /dev/null +++ b/spec/active_relation/relations/deletion_spec.rb @@ -0,0 +1,24 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Deletion do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql deleting a table relation' do + ActiveRelation::Relations::Deletion.new(@relation).to_sql.should be_like(""" + DELETE + FROM `users` + """) + end + + it 'manufactures sql deleting a selection relation' do + ActiveRelation::Relations::Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_spec.rb b/spec/active_relation/relations/insertion_spec.rb new file mode 100644 index 0000000000..da39edf773 --- /dev/null +++ b/spec/active_relation/relations/insertion_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Insertion do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql inserting the data for one item' do + ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + """) + end + + it 'manufactures sql inserting the data for multiple items' do + nested_insertion = ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "cobra") + ActiveRelation::Relations::Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('cobra'), ('commander') + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb new file mode 100644 index 0000000000..2a84a92b70 --- /dev/null +++ b/spec/active_relation/relations/join_spec.rb @@ -0,0 +1,43 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Join do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:id]) + end + + describe '==' do + it 'obtains if the two relations and the predicate are identical' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation1, @predicate) + end + + it 'is commutative on the relations' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation2, @relation1, @predicate) + end + end + + describe '#qualify' do + it 'distributes over the relations and predicates' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ + should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) + end + end + + describe '#to_sql' 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 + ActiveRelation::Relations::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 + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/relations/order_spec.rb new file mode 100644 index 0000000000..edf2faf455 --- /dev/null +++ b/spec/active_relation/relations/order_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Order do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end + + describe '#qualify' do + it "distributes over the relation and attributes" do + ActiveRelation::Relations::Order.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Order.new(@relation1.qualify, @attribute1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with an order clause" do + ActiveRelation::Relations::Order.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + ORDER BY `foo`.`id` + """) + end + end + +end \ No newline at end of file diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb new file mode 100644 index 0000000000..8ba571e06c --- /dev/null +++ b/spec/active_relation/relations/projection_spec.rb @@ -0,0 +1,34 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Projection do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end + + describe '==' do + it "obtains if the relations and attributes are identical" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation2, @attribute1) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation1, @attribute2) + end + end + + describe '#qualify' do + it "distributes over teh relation and attributes" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with a limited select clause" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`id` + FROM `foo` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb new file mode 100644 index 0000000000..d4107259aa --- /dev/null +++ b/spec/active_relation/relations/range_spec.rb @@ -0,0 +1,30 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Range do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @range1 = 1..2 + @range2 = 4..9 + end + + describe '#qualify' do + it "distributes over the relation and attributes" do + pending + end + end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + range_size = @range2.last - @range2.first + 1 + range_start = @range2.first + ActiveRelation::Relations::Range.new(@relation1, @range2).to_s.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + LIMIT #{range_size} + OFFSET #{range_start} + """) + end + end + +end \ No newline at end of file diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb new file mode 100644 index 0000000000..e52abab3a1 --- /dev/null +++ b/spec/active_relation/relations/rename_spec.rb @@ -0,0 +1,61 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Rename do + before do + @relation = ActiveRelation::Relations::Table.new(:foo) + @renamed_relation = ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid) + end + + describe '#initialize' do + it "manufactures nested rename relations if multiple renames are provided" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) + end + + it "raises an exception if the alias provided is already used" do + pending + end + end + + describe '==' do + it "obtains if the relation, attribute, and alias are identical" do + pending + end + end + + describe '#attributes' do + it "manufactures a list of attributes with the renamed attribute aliased" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == + (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] + end + end + + describe '[]' do + it 'indexes attributes by alias' do + @renamed_relation[:id].should be_nil + @renamed_relation[:schmid].should == @relation[:id].alias(:schmid) + end + end + + describe '#schmattribute' do + it "should be renamed" do + pending + end + end + + describe '#qualify' do + it "distributes over the relation and renames" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).qualify. \ + should == ActiveRelation::Relations::Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + end + end + + describe '#to_sql' do + it 'manufactures sql aliasing the attribute' do + @renamed_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` AS 'schmid' + FROM `foo` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/relations/selection_spec.rb new file mode 100644 index 0000000000..90dc3169b6 --- /dev/null +++ b/spec/active_relation/relations/selection_spec.rb @@ -0,0 +1,42 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Selection do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate1 = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:foo_id]) + @predicate2 = ActiveRelation::Predicates::LessThan.new(@relation1[:age], 2) + end + + describe '#initialize' do + it "manufactures nested selection relations if multiple predicates are provided" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1, @predicate2). \ + should == ActiveRelation::Relations::Selection.new(ActiveRelation::Relations::Selection.new(@relation1, @predicate2), @predicate1) + end + end + + describe '#qualify' do + it "distributes over the relation and predicates" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).qualify. \ + should == ActiveRelation::Relations::Selection.new(@relation1.qualify, @predicate1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with where clause conditions" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE `foo`.`id` = `bar`.`foo_id` + """) + end + + it "allows arbitrary sql" do + ActiveRelation::Relations::Selection.new(@relation1, "asdf").to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE asdf + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb new file mode 100644 index 0000000000..62b8e44980 --- /dev/null +++ b/spec/active_relation/relations/table_spec.rb @@ -0,0 +1,30 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Table do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it "returns a simple SELECT query" do + @relation.to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id` + FROM `users` + """) + end + end + + describe '#attributes' do + it 'manufactures attributes corresponding to columns in the table' do + pending + end + end + + describe '#qualify' do + it 'manufactures a rename relation with all attribute names qualified' do + @relation.qualify.should == ActiveRelation::Relations::Rename.new( + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' + ) + end + end +end \ No newline at end of file