From e13420c86afb5c31e90cff800f121bd49255b939 Mon Sep 17 00:00:00 2001
From: Carl Lerche <carllerche@mac.com>
Date: Fri, 12 Mar 2010 14:46:37 -0800
Subject: We're obviously writing specs for arel. No need for a sub directory.

---
 spec/algebra/integration/basic_spec.rb          |  85 +++++++++++
 spec/algebra/unit/predicates/binary_spec.rb     |  35 +++++
 spec/algebra/unit/predicates/equality_spec.rb   |  29 ++++
 spec/algebra/unit/predicates/in_spec.rb         |  12 ++
 spec/algebra/unit/primitives/attribute_spec.rb  | 181 +++++++++++++++++++++++
 spec/algebra/unit/primitives/expression_spec.rb |  45 ++++++
 spec/algebra/unit/primitives/value_spec.rb      |  15 ++
 spec/algebra/unit/relations/alias_spec.rb       |  16 ++
 spec/algebra/unit/relations/delete_spec.rb      |   9 ++
 spec/algebra/unit/relations/group_spec.rb       |  10 ++
 spec/algebra/unit/relations/insert_spec.rb      |   9 ++
 spec/algebra/unit/relations/join_spec.rb        |  26 ++++
 spec/algebra/unit/relations/order_spec.rb       |  21 +++
 spec/algebra/unit/relations/project_spec.rb     |  34 +++++
 spec/algebra/unit/relations/relation_spec.rb    | 187 ++++++++++++++++++++++++
 spec/algebra/unit/relations/skip_spec.rb        |  10 ++
 spec/algebra/unit/relations/table_spec.rb       |  38 +++++
 spec/algebra/unit/relations/take_spec.rb        |  10 ++
 spec/algebra/unit/relations/update_spec.rb      |   9 ++
 spec/algebra/unit/relations/where_spec.rb       |  18 +++
 spec/algebra/unit/session/session_spec.rb       |  84 +++++++++++
 21 files changed, 883 insertions(+)
 create mode 100644 spec/algebra/integration/basic_spec.rb
 create mode 100644 spec/algebra/unit/predicates/binary_spec.rb
 create mode 100644 spec/algebra/unit/predicates/equality_spec.rb
 create mode 100644 spec/algebra/unit/predicates/in_spec.rb
 create mode 100644 spec/algebra/unit/primitives/attribute_spec.rb
 create mode 100644 spec/algebra/unit/primitives/expression_spec.rb
 create mode 100644 spec/algebra/unit/primitives/value_spec.rb
 create mode 100644 spec/algebra/unit/relations/alias_spec.rb
 create mode 100644 spec/algebra/unit/relations/delete_spec.rb
 create mode 100644 spec/algebra/unit/relations/group_spec.rb
 create mode 100644 spec/algebra/unit/relations/insert_spec.rb
 create mode 100644 spec/algebra/unit/relations/join_spec.rb
 create mode 100644 spec/algebra/unit/relations/order_spec.rb
 create mode 100644 spec/algebra/unit/relations/project_spec.rb
 create mode 100644 spec/algebra/unit/relations/relation_spec.rb
 create mode 100644 spec/algebra/unit/relations/skip_spec.rb
 create mode 100644 spec/algebra/unit/relations/table_spec.rb
 create mode 100644 spec/algebra/unit/relations/take_spec.rb
 create mode 100644 spec/algebra/unit/relations/update_spec.rb
 create mode 100644 spec/algebra/unit/relations/where_spec.rb
 create mode 100644 spec/algebra/unit/session/session_spec.rb

(limited to 'spec/algebra')

diff --git a/spec/algebra/integration/basic_spec.rb b/spec/algebra/integration/basic_spec.rb
new file mode 100644
index 0000000000..7aa4f7305c
--- /dev/null
+++ b/spec/algebra/integration/basic_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+def have_rows(expected)
+  simple_matcher "have rows" do |given, matcher|
+    found, got, expected = [], [], expected.map { |r| r.tuple }
+    given.each do |row|
+      got << row.tuple
+      found << expected.find { |r| row.tuple == r }
+    end
+
+    matcher.failure_message = "Expected to get:\n" \
+      "#{expected.map {|r| "  #{r.inspect}" }.join("\n")}\n" \
+      "instead, got:\n" \
+      "#{got.map {|r| "  #{r.inspect}" }.join("\n")}"
+    
+    found.compact.length == expected.length && got.compact.length == expected.length
+  end
+end
+
+share_examples_for 'A Relation' do
+
+  before :all do
+    # The two needed instance variables need to be set in a
+    # before :all callback.
+    #   @relation is the relation being tested here.
+    #   @expected is an array of the elements that are expected to be in
+    #     the relation.
+    %w[ @relation @expected ].each do |ivar|
+      raise "#{ivar} needs to be defined" unless instance_variable_get(ivar)
+    end
+
+    # There needs to be enough items to be able to run all the tests
+    raise "@expected needs to have at least 6 items" unless @expected.length >= 6
+  end
+
+  describe "#each" do
+    it "iterates over the rows in any order" do
+      @relation.should have_rows(@expected)
+    end
+  end
+
+  describe "#where" do
+    before :all do
+      @expected = @expected.sort_by { |r| r[@relation[:age]] }
+      @pivot = @expected[@expected.length / 2]
+    end
+
+    it "finds rows with an equal to predicate" do
+      expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] }
+      @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected)
+    end
+  end
+end
+
+module Arel
+  describe "Relation" do
+
+    before :all do
+      @engine = Testing::Engine.new
+      @relation = Model.build do |r|
+        r.engine @engine
+
+        r.attribute :id,   Attributes::Integer
+        r.attribute :name, Attributes::String
+        r.attribute :age,  Attributes::Integer
+      end
+    end
+
+    describe "..." do
+      before :all do
+        @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) }
+      end
+
+      it_should_behave_like 'A Relation'
+    end
+
+    describe "#insert" do
+      it "inserts the row into the engine" do
+        @relation.insert([1, 'Foo', 10])
+        @engine.rows.should == [[1, 'Foo', 10]]
+      end
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/spec/algebra/unit/predicates/binary_spec.rb b/spec/algebra/unit/predicates/binary_spec.rb
new file mode 100644
index 0000000000..051aeeeb6e
--- /dev/null
+++ b/spec/algebra/unit/predicates/binary_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+module Arel
+  module Predicates
+    describe Binary do
+      before do
+        @relation = Arel::Table.new(:users)
+        @attribute1 = @relation[:id]
+        @attribute2 = @relation[:name]
+        class ConcreteBinary < Binary
+        end
+      end
+
+      describe '#bind' do
+        before do
+          @another_relation = @relation.alias
+        end
+
+        describe 'when both operands are attributes' do
+          it "manufactures an expression with the attributes bound to the relation" do
+            ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \
+              should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2])
+          end
+        end
+
+        describe 'when an operand is a value' do
+          it "manufactures an expression with unmodified values" do
+            ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \
+              should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation))
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/predicates/equality_spec.rb b/spec/algebra/unit/predicates/equality_spec.rb
new file mode 100644
index 0000000000..7d1d79ff35
--- /dev/null
+++ b/spec/algebra/unit/predicates/equality_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+module Arel
+  module Predicates
+    describe Equality do
+      before do
+        @relation1 = Arel::Table.new(:users)
+        @relation2 = Arel::Table.new(:photos)
+        @attribute1 = @relation1[:id]
+        @attribute2 = @relation2[:user_id]
+      end
+
+      describe '==' do
+        it "obtains if attribute1 and attribute2 are identical" do
+          check Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2)
+          Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1)
+        end
+
+        it "obtains if the concrete type of the predicates are identical" do
+          Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2)
+        end
+
+        it "is commutative on the attributes" do
+          Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/predicates/in_spec.rb b/spec/algebra/unit/predicates/in_spec.rb
new file mode 100644
index 0000000000..b9e15d63a4
--- /dev/null
+++ b/spec/algebra/unit/predicates/in_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+module Arel
+  module Predicates
+    describe In do
+      before do
+        @relation = Table.new(:users)
+        @attribute = @relation[:id]
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb
new file mode 100644
index 0000000000..f734cc9c38
--- /dev/null
+++ b/spec/algebra/unit/primitives/attribute_spec.rb
@@ -0,0 +1,181 @@
+require 'spec_helper'
+
+module Arel
+  describe Attribute do
+    before do
+      @relation = Table.new(:users)
+      @attribute = @relation[:id]
+    end
+
+    describe "#inspect" do
+      it "returns a simple, short inspect string" do
+        @attribute.inspect.should == "<Attribute id>"
+      end
+    end
+
+    describe Attribute::Transformations do
+      describe '#as' do
+        it "manufactures an aliased attributed" do
+          @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute)
+        end
+      end
+
+      describe '#bind' do
+        it "manufactures an attribute with the relation bound and self as an ancestor" do
+          derived_relation = @relation.where(@relation[:id].eq(1))
+          @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute)
+        end
+
+        it "returns self if the substituting to the same relation" do
+          @attribute.bind(@relation).should == @attribute
+        end
+      end
+
+      describe '#to_attribute' do
+        describe 'when the given relation is the same as the attributes relation' do
+          it "returns self" do
+            @attribute.to_attribute(@relation).should == @attribute
+          end
+        end
+
+        describe 'when the given relation differs from the attributes relation' do
+          it 'binds to the new relation' do
+            @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation)
+          end
+        end
+      end
+    end
+
+    describe '#column' do
+      it "returns the corresponding column in the relation" do
+        @attribute.column.should == @relation.column_for(@attribute)
+      end
+    end
+
+    describe '#engine' do
+      it "delegates to its relation" do
+        Attribute.new(@relation, :id).engine.should == @relation.engine
+      end
+    end
+
+    describe Attribute::Congruence do
+      describe '/' do
+        before do
+          @aliased_relation = @relation.alias
+          @doubly_aliased_relation = @aliased_relation.alias
+        end
+
+        describe 'when dividing two unrelated attributes' do
+          it "returns 0.0" do
+            (@relation[:id] / @relation[:name]).should == 0.0
+          end
+        end
+
+        describe 'when dividing two matching attributes' do
+          it 'returns a the highest score for the most similar attributes' do
+            check((@aliased_relation[:id] / @relation[:id]).should == (@aliased_relation[:id] / @relation[:id]))
+            (@aliased_relation[:id] / @relation[:id]).should < (@aliased_relation[:id] / @aliased_relation[:id])
+          end
+        end
+      end
+    end
+
+    describe Attribute::Predications do
+      before do
+        @attribute = Attribute.new(@relation, :name)
+      end
+
+      describe '#eq' do
+        it "manufactures an equality predicate" do
+          @attribute.eq('name').should == Predicates::Equality.new(@attribute, 'name')
+        end
+      end
+
+      describe '#lt' do
+        it "manufactures a less-than predicate" do
+          @attribute.lt(10).should == Predicates::LessThan.new(@attribute, 10)
+        end
+      end
+
+      describe '#lteq' do
+        it "manufactures a less-than or equal-to predicate" do
+          @attribute.lteq(10).should == Predicates::LessThanOrEqualTo.new(@attribute, 10)
+        end
+      end
+
+      describe '#gt' do
+        it "manufactures a greater-than predicate" do
+          @attribute.gt(10).should == Predicates::GreaterThan.new(@attribute, 10)
+        end
+      end
+
+      describe '#gteq' do
+        it "manufactures a greater-than or equal-to predicate" do
+          @attribute.gteq(10).should == Predicates::GreaterThanOrEqualTo.new(@attribute, 10)
+        end
+      end
+
+      describe '#matches' do
+        it "manufactures a match predicate" do
+          @attribute.matches(/.*/).should == Predicates::Match.new(@attribute, /.*/)
+        end
+      end
+
+      describe '#in' do
+        it "manufactures an in predicate" do
+          @attribute.in(1..30).should == Predicates::In.new(@attribute, (1..30))
+        end
+      end
+    end
+
+    describe Attribute::Expressions do
+      before do
+        @attribute = Attribute.new(@relation, :name)
+      end
+
+      describe '#count' do
+        it "manufactures a count Expression" do
+          @attribute.count.should == Count.new(@attribute)
+        end
+      end
+
+      describe '#sum' do
+        it "manufactures a sum Expression" do
+          @attribute.sum.should == Sum.new(@attribute)
+        end
+      end
+
+      describe '#maximum' do
+        it "manufactures a maximum Expression" do
+          @attribute.maximum.should == Maximum.new(@attribute)
+        end
+      end
+
+      describe '#minimum' do
+        it "manufactures a minimum Expression" do
+          @attribute.minimum.should == Minimum.new(@attribute)
+        end
+      end
+
+      describe '#average' do
+        it "manufactures an average Expression" do
+          @attribute.average.should == Average.new(@attribute)
+        end
+      end
+    end
+
+    describe Attribute::Orderings do
+      describe '#asc' do
+        it 'manufactures an ascending ordering' do
+          @attribute.asc.should == Ascending.new(@attribute)
+        end
+      end
+
+      describe '#desc' do
+        it 'manufactures a descending ordering' do
+          @attribute.desc.should == Descending.new(@attribute)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/primitives/expression_spec.rb b/spec/algebra/unit/primitives/expression_spec.rb
new file mode 100644
index 0000000000..ac932ed139
--- /dev/null
+++ b/spec/algebra/unit/primitives/expression_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+module Arel
+  describe Expression do
+    before do
+      @relation = Table.new(:users)
+      @attribute = @relation[:id]
+    end
+
+    describe "#inspect" do
+      it "returns a simple, short inspect string" do
+        @attribute.count.inspect.should == "<Arel::Count <Attribute id>>"
+      end
+    end
+
+    describe Expression::Transformations do
+      before do
+        @expression = Count.new(@attribute)
+      end
+
+      describe '#bind' do
+        it "manufactures an attribute with a rebound relation and self as the ancestor" do
+          derived_relation = @relation.where(@relation[:id].eq(1))
+          @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression)
+        end
+
+        it "returns self if the substituting to the same relation" do
+          @expression.bind(@relation).should == @expression
+        end
+      end
+
+      describe '#as' do
+        it "manufactures an aliased expression" do
+          @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression)
+        end
+      end
+
+      describe '#to_attribute' do
+        it "manufactures an attribute with the expression as an ancestor" do
+          @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/primitives/value_spec.rb b/spec/algebra/unit/primitives/value_spec.rb
new file mode 100644
index 0000000000..8fed752d66
--- /dev/null
+++ b/spec/algebra/unit/primitives/value_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+module Arel
+  describe Value do
+    before do
+      @relation = Table.new(:users)
+    end
+
+    describe '#bind' do
+      it "manufactures a new value whose relation is the provided relation" do
+        Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation)
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/alias_spec.rb b/spec/algebra/unit/relations/alias_spec.rb
new file mode 100644
index 0000000000..eaf31652b9
--- /dev/null
+++ b/spec/algebra/unit/relations/alias_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+module Arel
+  describe Alias do
+    before do
+      @relation = Table.new(:users)
+    end
+
+    describe '==' do
+      it "obtains if the objects are the same" do
+        check Alias.new(@relation).should_not == Alias.new(@relation)
+        (aliaz = Alias.new(@relation)).should == aliaz
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/delete_spec.rb b/spec/algebra/unit/relations/delete_spec.rb
new file mode 100644
index 0000000000..c244be8631
--- /dev/null
+++ b/spec/algebra/unit/relations/delete_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+module Arel
+  describe Deletion do
+    before do
+      @relation = Table.new(:users)
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/group_spec.rb b/spec/algebra/unit/relations/group_spec.rb
new file mode 100644
index 0000000000..48fc818682
--- /dev/null
+++ b/spec/algebra/unit/relations/group_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+
+module Arel
+  describe Group do
+    before do
+      @relation = Table.new(:users)
+      @attribute = @relation[:id]
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/insert_spec.rb b/spec/algebra/unit/relations/insert_spec.rb
new file mode 100644
index 0000000000..3141fa2fc4
--- /dev/null
+++ b/spec/algebra/unit/relations/insert_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+module Arel
+  describe Insert do
+    before do
+      @relation = Table.new(:users)
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/join_spec.rb b/spec/algebra/unit/relations/join_spec.rb
new file mode 100644
index 0000000000..9c1422c571
--- /dev/null
+++ b/spec/algebra/unit/relations/join_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+module Arel
+  describe Join do
+    before do
+      @relation1 = Table.new(:users)
+      @relation2 = Table.new(:photos)
+      @predicate = @relation1[:id].eq(@relation2[:user_id])
+    end
+
+    describe 'hashing' do
+      it 'implements hash equality' do
+        InnerJoin.new(@relation1, @relation2, @predicate) \
+          .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate))
+      end
+    end
+
+    describe '#attributes' do
+      it 'combines the attributes of the two relations' do
+        join = InnerJoin.new(@relation1, @relation2, @predicate)
+        join.attributes.should ==
+          (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) }
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/order_spec.rb b/spec/algebra/unit/relations/order_spec.rb
new file mode 100644
index 0000000000..9fcdffe340
--- /dev/null
+++ b/spec/algebra/unit/relations/order_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+module Arel
+  describe Order do
+    before do
+      @relation = Table.new(:users)
+      @attribute = @relation[:id]
+    end
+
+    describe "#==" do
+      it "returns true when the Orders are for the same attribute and direction" do
+        Ascending.new(@attribute).should == Ascending.new(@attribute)
+      end
+
+      it "returns false when the Orders are for a diferent direction" do
+        Ascending.new(@attribute).should_not == Descending.new(@attribute)
+      end
+    end
+  end
+end
+
diff --git a/spec/algebra/unit/relations/project_spec.rb b/spec/algebra/unit/relations/project_spec.rb
new file mode 100644
index 0000000000..8886e65a2e
--- /dev/null
+++ b/spec/algebra/unit/relations/project_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+module Arel
+  describe Project do
+    before do
+      @relation = Table.new(:users)
+      @attribute = @relation[:id]
+    end
+
+    describe '#attributes' do
+      before do
+        @projection = Project.new(@relation, @attribute)
+      end
+
+      it "manufactures attributes associated with the projection relation" do
+        @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) }
+      end
+    end
+
+    describe '#externalizable?' do
+      describe 'when the projections are attributes' do
+        it 'returns false' do
+          Project.new(@relation, @attribute).should_not be_externalizable
+        end
+      end
+
+      describe 'when the projections include an aggregation' do
+        it "obtains" do
+          Project.new(@relation, @attribute.sum).should be_externalizable
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb
new file mode 100644
index 0000000000..a1d1793d92
--- /dev/null
+++ b/spec/algebra/unit/relations/relation_spec.rb
@@ -0,0 +1,187 @@
+require 'spec_helper'
+
+module Arel
+  describe Relation do
+    before do
+      @relation = Table.new(:users)
+      @attribute1 = @relation[:id]
+      @attribute2 = @relation[:name]
+    end
+
+    describe '[]' do
+      describe 'when given an', Attribute do
+        it "return the attribute congruent to the provided attribute" do
+          @relation[@attribute1].should == @attribute1
+        end
+      end
+
+      describe 'when given a', Symbol, String do
+        it "returns the attribute with the same name" do
+          check @relation[:id].should == @attribute1
+          check @relation['id'].should == @attribute1
+        end
+      end
+    end
+
+    describe Relation::Operable do
+      describe 'joins' do
+        before do
+          @predicate = @relation[:id].eq(@relation[:id])
+        end
+
+        describe '#join' do
+          describe 'when given a relation' do
+            it "manufactures an inner join operation between those two relations" do
+              @relation.join(@relation).on(@predicate). \
+                should == InnerJoin.new(@relation, @relation, @predicate)
+            end
+          end
+
+          describe "when given a string" do
+            it "manufactures a join operation with the string passed through" do
+              @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string)
+            end
+          end
+
+          describe "when given something blank" do
+            it "returns self" do
+              @relation.join.should == @relation
+            end
+          end
+        end
+
+        describe '#outer_join' do
+          it "manufactures a left outer join operation between those two relations" do
+            @relation.outer_join(@relation).on(@predicate). \
+              should == OuterJoin.new(@relation, @relation, @predicate)
+          end
+        end
+      end
+
+      describe '#project' do
+        it "manufactures a projection relation" do
+          @relation.project(@attribute1, @attribute2). \
+            should == Project.new(@relation, @attribute1, @attribute2)
+        end
+
+        describe "when given blank attributes" do
+          it "returns self" do
+            @relation.project.should == @relation
+          end
+        end
+      end
+
+      describe '#alias' do
+        it "manufactures an alias relation" do
+          @relation.alias.relation.should == Alias.new(@relation).relation
+        end
+      end
+
+      describe '#where' do
+        before do
+          @predicate = Predicates::Equality.new(@attribute1, @attribute2)
+        end
+
+        it "manufactures a where relation" do
+          @relation.where(@predicate).should == Where.new(@relation, @predicate)
+        end
+
+        it "accepts arbitrary strings" do
+          @relation.where("arbitrary").should == Where.new(@relation, "arbitrary")
+        end
+
+        describe 'when given a blank predicate' do
+          it 'returns self' do
+            @relation.where.should == @relation
+          end
+        end
+      end
+
+      describe '#order' do
+        it "manufactures an order relation" do
+          @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2)
+        end
+
+        describe 'when given a blank ordering' do
+          it 'returns self' do
+            @relation.order.should == @relation
+          end
+        end
+      end
+
+      describe '#take' do
+        it "manufactures a take relation" do
+          @relation.take(5).should == Take.new(@relation, 5)
+        end
+
+        describe 'when given a blank number of items' do
+          it 'returns self' do
+            @relation.take.should == @relation
+          end
+        end
+      end
+
+      describe '#skip' do
+        it "manufactures a skip relation" do
+          @relation.skip(4).should == Skip.new(@relation, 4)
+        end
+
+        describe 'when given a blank number of items' do
+          it 'returns self' do
+            @relation.skip.should == @relation
+          end
+        end
+      end
+
+      describe '#group' do
+        it 'manufactures a group relation' do
+          @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2)
+        end
+
+        describe 'when given blank groupings' do
+          it 'returns self' do
+            @relation.group.should == @relation
+          end
+        end
+      end
+
+      describe Relation::Operable::Writable do
+        describe '#delete' do
+          it 'manufactures a deletion relation' do
+            Session.start do
+              Session.new.should_receive(:delete).with(Deletion.new(@relation))
+              @relation.delete
+            end
+          end
+        end
+
+        describe '#insert' do
+          it 'manufactures an insertion relation' do
+            Session.start do
+              record = { @relation[:name] => 'carl' }
+              Session.new.should_receive(:create).with(Insert.new(@relation, record))
+              @relation.insert(record)
+            end
+          end
+        end
+
+        describe '#update' do
+          it 'manufactures an update relation' do
+            Session.start do
+              assignments = { @relation[:name] => Value.new('bob', @relation) }
+              Session.new.should_receive(:update).with(Update.new(@relation, assignments))
+              @relation.update(assignments)
+            end
+          end
+        end
+      end
+    end
+
+    describe Relation::Enumerable do
+      it "implements enumerable" do
+        @relation.map { |value| value }.should ==
+        @relation.session.read(@relation).map { |value| value }
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/skip_spec.rb b/spec/algebra/unit/relations/skip_spec.rb
new file mode 100644
index 0000000000..e7dea6c1cf
--- /dev/null
+++ b/spec/algebra/unit/relations/skip_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+
+module Arel
+  describe Skip do
+    before do
+      @relation = Table.new(:users)
+      @skipped = 4
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/table_spec.rb b/spec/algebra/unit/relations/table_spec.rb
new file mode 100644
index 0000000000..d93446f1b9
--- /dev/null
+++ b/spec/algebra/unit/relations/table_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+module Arel
+  describe Table do
+    before do
+      @relation = Table.new(:users)
+    end
+
+    describe '[]' do
+      describe 'when given a', Symbol do
+        it "manufactures an attribute if the symbol names an attribute within the relation" do
+          check @relation[:id].should == Attribute.new(@relation, :id)
+        end
+      end
+
+      describe 'when given an', Attribute do
+        it "returns the attribute if the attribute is within the relation" do
+          @relation[@relation[:id]].should == @relation[:id]
+        end
+
+        it "returns nil if the attribtue is not within the relation" do
+          another_relation = Table.new(:photos)
+          @relation[another_relation[:id]].should be_nil
+        end
+      end
+
+      describe 'when given an', Expression do
+        before do
+          @expression = @relation[:id].count
+        end
+
+        it "returns the Expression if the Expression is within the relation" do
+          @relation[@expression].should be_nil
+        end
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/take_spec.rb b/spec/algebra/unit/relations/take_spec.rb
new file mode 100644
index 0000000000..3ad8d269f1
--- /dev/null
+++ b/spec/algebra/unit/relations/take_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+
+module Arel
+  describe Take do
+    before do
+      @relation = Table.new(:users)
+      @taken = 4
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/update_spec.rb b/spec/algebra/unit/relations/update_spec.rb
new file mode 100644
index 0000000000..9ed20a446b
--- /dev/null
+++ b/spec/algebra/unit/relations/update_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+module Arel
+  describe Update do
+    before do
+      @relation = Table.new(:users)
+    end
+  end
+end
diff --git a/spec/algebra/unit/relations/where_spec.rb b/spec/algebra/unit/relations/where_spec.rb
new file mode 100644
index 0000000000..96b95b5823
--- /dev/null
+++ b/spec/algebra/unit/relations/where_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+module Arel
+  describe Where do
+    before do
+      @relation = Table.new(:users)
+      @predicate = @relation[:id].eq(1)
+    end
+
+    describe '#initialize' do
+      it "manufactures nested where relations if multiple predicates are provided" do
+        another_predicate = @relation[:name].lt(2)
+        Where.new(@relation, @predicate, another_predicate). \
+          should == Where.new(Where.new(@relation, another_predicate), @predicate)
+      end
+    end
+  end
+end
diff --git a/spec/algebra/unit/session/session_spec.rb b/spec/algebra/unit/session/session_spec.rb
new file mode 100644
index 0000000000..0553a140ec
--- /dev/null
+++ b/spec/algebra/unit/session/session_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+module Arel
+  describe Session do
+    before do
+      @relation = Table.new(:users)
+      @session = Session.new
+    end
+
+    describe '::start' do
+      describe '::instance' do
+        it "it is a singleton within the started session" do
+          Session.start do
+            Session.new.should == Session.new
+          end
+        end
+
+        it "is a singleton across nested sessions" do
+          Session.start do
+            outside = Session.new
+            Session.start do
+              Session.new.should == outside
+            end
+          end
+        end
+
+        it "manufactures new sessions outside of the started session" do
+          Session.new.should_not == Session.new
+        end
+      end
+    end
+
+    describe Session::CRUD do
+      before do
+        @insert = Insert.new(@relation, @relation[:name] => 'nick')
+        @update = Update.new(@relation, @relation[:name] => 'nick')
+        @delete = Deletion.new(@relation)
+        @read = @relation
+      end
+
+      describe '#create' do
+        it "executes an insertion on the connection" do
+          @insert.should_receive(:call)
+          @session.create(@insert)
+        end
+      end
+
+      describe '#read' do
+        it "executes an selection on the connection" do
+          @read.should_receive(:call)
+          @session.read(@read)
+        end
+
+        it "is memoized" do
+          @read.should_receive(:call).once
+          @session.read(@read)
+          @session.read(@read)
+        end
+      end
+
+      describe '#update' do
+        it "executes an update on the connection" do
+          @update.should_receive(:call)
+          @session.update(@update)
+        end
+      end
+
+      describe '#delete' do
+        it "executes a delete on the connection" do
+          @delete.should_receive(:call)
+          @session.delete(@delete)
+        end
+      end
+    end
+
+    describe 'Transactions' do
+      describe '#begin' do
+      end
+
+      describe '#end' do
+      end
+    end
+  end
+end
-- 
cgit v1.2.3