aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/attributes/test_attribute.rb648
-rw-r--r--test/nodes/test_count.rb18
-rw-r--r--test/nodes/test_delete_statement.rb14
-rw-r--r--test/nodes/test_equality.rb74
-rw-r--r--test/nodes/test_insert_statement.rb18
-rw-r--r--test/nodes/test_or.rb22
-rw-r--r--test/nodes/test_select_core.rb22
-rw-r--r--test/nodes/test_select_statement.rb13
-rw-r--r--test/nodes/test_sql_literal.rb28
-rw-r--r--test/nodes/test_sum.rb12
-rw-r--r--test/nodes/test_update_statement.rb18
-rw-r--r--test/spec_helper.rb21
-rw-r--r--test/support/fake_record.rb89
-rw-r--r--test/test_activerecord_compat.rb18
-rw-r--r--test/test_attributes.rb41
-rw-r--r--test/test_crud.rb69
-rw-r--r--test/test_delete_manager.rb54
-rw-r--r--test/test_insert_manager.rb140
-rw-r--r--test/test_select_manager.rb593
-rw-r--r--test/test_table.rb175
-rw-r--r--test/test_update_manager.rb90
-rw-r--r--test/visitors/test_join_sql.rb35
-rw-r--r--test/visitors/test_oracle.rb111
-rw-r--r--test/visitors/test_postgres.rb17
-rw-r--r--test/visitors/test_to_sql.rb134
25 files changed, 2474 insertions, 0 deletions
diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb
new file mode 100644
index 0000000000..f0341f4070
--- /dev/null
+++ b/test/attributes/test_attribute.rb
@@ -0,0 +1,648 @@
+require 'spec_helper'
+
+module Arel
+ module Attributes
+ describe 'attribute' do
+ describe '#not_eq' do
+ it 'should create a NotEqual node' do
+ relation = Table.new(:users)
+ relation[:id].not_eq(10).must_be_kind_of Nodes::NotEqual
+ end
+
+ it 'should generate != in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_eq(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" != 10
+ }
+ end
+
+ it 'should handle nil' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_eq(nil)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" IS NOT NULL
+ }
+ end
+ end
+
+ describe '#not_eq_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].not_eq_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_eq_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 OR "users"."id" != 2)
+ }
+ end
+ end
+
+ describe '#not_eq_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].not_eq_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_eq_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 AND "users"."id" != 2)
+ }
+ end
+ end
+
+ describe '#gt' do
+ it 'should create a GreaterThan node' do
+ relation = Table.new(:users)
+ relation[:id].gt(10).must_be_kind_of Nodes::GreaterThan
+ end
+
+ it 'should generate >= in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gt(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" > 10
+ }
+ end
+ end
+
+ describe '#gt_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].gt_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gt_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 OR "users"."id" > 2)
+ }
+ end
+ end
+
+ describe '#gt_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].gt_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gt_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 AND "users"."id" > 2)
+ }
+ end
+ end
+
+ describe '#gteq' do
+ it 'should create a GreaterThanOrEqual node' do
+ relation = Table.new(:users)
+ relation[:id].gteq(10).must_be_kind_of Nodes::GreaterThanOrEqual
+ end
+
+ it 'should generate >= in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gteq(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10
+ }
+ end
+ end
+
+ describe '#gteq_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].gteq_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gteq_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 OR "users"."id" >= 2)
+ }
+ end
+ end
+
+ describe '#gteq_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].gteq_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].gteq_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 AND "users"."id" >= 2)
+ }
+ end
+ end
+
+ describe '#lt' do
+ it 'should create a LessThan node' do
+ relation = Table.new(:users)
+ relation[:id].lt(10).must_be_kind_of Nodes::LessThan
+ end
+
+ it 'should generate < in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lt(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" < 10
+ }
+ end
+ end
+
+ describe '#lt_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].lt_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lt_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 OR "users"."id" < 2)
+ }
+ end
+ end
+
+ describe '#lt_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].lt_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lt_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 AND "users"."id" < 2)
+ }
+ end
+ end
+
+ describe '#lteq' do
+ it 'should create a LessThanOrEqual node' do
+ relation = Table.new(:users)
+ relation[:id].lteq(10).must_be_kind_of Nodes::LessThanOrEqual
+ end
+
+ it 'should generate <= in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lteq(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10
+ }
+ end
+ end
+
+ describe '#lteq_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].lteq_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lteq_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 OR "users"."id" <= 2)
+ }
+ end
+ end
+
+ describe '#lteq_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].lteq_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].lteq_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 AND "users"."id" <= 2)
+ }
+ end
+ end
+
+ describe '#average' do
+ it 'should create a AVG node' do
+ relation = Table.new(:users)
+ relation[:id].average.must_be_kind_of Nodes::Avg
+ end
+
+ # FIXME: backwards compat. Is this really necessary?
+ it 'should set the alias to "avg_id"' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id].average
+ mgr.to_sql.must_be_like %{
+ SELECT AVG("users"."id") AS avg_id
+ FROM "users"
+ }
+ end
+ end
+
+ describe '#maximum' do
+ it 'should create a MAX node' do
+ relation = Table.new(:users)
+ relation[:id].maximum.must_be_kind_of Nodes::Max
+ end
+
+ # FIXME: backwards compat. Is this really necessary?
+ it 'should set the alias to "max_id"' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id].maximum
+ mgr.to_sql.must_be_like %{
+ SELECT MAX("users"."id") AS max_id
+ FROM "users"
+ }
+ end
+ end
+
+ describe '#minimum' do
+ it 'should create a Min node' do
+ relation = Table.new(:users)
+ relation[:id].minimum.must_be_kind_of Nodes::Min
+ end
+ end
+
+ describe '#sum' do
+ it 'should create a SUM node' do
+ relation = Table.new(:users)
+ relation[:id].sum.must_be_kind_of Nodes::Sum
+ end
+
+ # FIXME: backwards compat. Is this really necessary?
+ it 'should set the alias to "sum_id"' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id].sum
+ mgr.to_sql.must_be_like %{
+ SELECT SUM("users"."id") AS sum_id
+ FROM "users"
+ }
+ end
+ end
+
+ describe '#count' do
+ it 'should return a count node' do
+ relation = Table.new(:users)
+ relation[:id].count.must_be_kind_of Nodes::Count
+ end
+
+ it 'should take a distinct param' do
+ relation = Table.new(:users)
+ count = relation[:id].count(nil)
+ count.must_be_kind_of Nodes::Count
+ count.distinct.must_be_nil
+ end
+ end
+
+ describe '#eq' do
+ it 'should return an equality node' do
+ attribute = Attribute.new nil, nil, nil
+ equality = attribute.eq 1
+ check equality.left.must_equal attribute
+ check equality.right.must_equal 1
+ equality.must_be_kind_of Nodes::Equality
+ end
+
+ it 'should generate = in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].eq(10)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" = 10
+ }
+ end
+
+ it 'should handle nil' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].eq(nil)
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" IS NULL
+ }
+ end
+ end
+
+ describe '#eq_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].eq_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].eq_any([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 OR "users"."id" = 2)
+ }
+ end
+ end
+
+ describe '#eq_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].eq_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].eq_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2)
+ }
+ end
+ end
+
+ describe '#matches' do
+ it 'should create a Matches node' do
+ relation = Table.new(:users)
+ relation[:name].matches('%bacon%').must_be_kind_of Nodes::Matches
+ end
+
+ it 'should generate LIKE in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].matches('%bacon%')
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."name" LIKE '%bacon%'
+ }
+ end
+ end
+
+ describe '#matches_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:name].matches_any(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].matches_any(['%chunky%','%bacon%'])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' OR "users"."name" LIKE '%bacon%')
+ }
+ end
+ end
+
+ describe '#matches_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:name].matches_all(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].matches_all(['%chunky%','%bacon%'])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' AND "users"."name" LIKE '%bacon%')
+ }
+ end
+ end
+
+ describe '#does_not_match' do
+ it 'should create a DoesNotMatch node' do
+ relation = Table.new(:users)
+ relation[:name].does_not_match('%bacon%').must_be_kind_of Nodes::DoesNotMatch
+ end
+
+ it 'should generate NOT LIKE in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].does_not_match('%bacon%')
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."name" NOT LIKE '%bacon%'
+ }
+ end
+ end
+
+ describe '#does_not_match_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:name].does_not_match_any(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].does_not_match_any(['%chunky%','%bacon%'])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' OR "users"."name" NOT LIKE '%bacon%')
+ }
+ end
+ end
+
+ describe '#does_not_match_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:name].does_not_match_all(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%'])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' AND "users"."name" NOT LIKE '%bacon%')
+ }
+ end
+ end
+
+ describe '#in' do
+ it 'can be constructed with a list' do
+ end
+
+ it 'should return an in node' do
+ attribute = Attribute.new nil, nil, nil
+ node = Nodes::In.new attribute, [1,2,3]
+ check node.left.must_equal attribute
+ check node.right.must_equal [1, 2, 3]
+ end
+
+ it 'should generate IN in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].in([1,2,3])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" IN (1, 2, 3)
+ }
+ end
+ end
+
+ describe '#in_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].in_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].in_any([[1,2], [3,4]])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) OR "users"."id" IN (3, 4))
+ }
+ end
+ end
+
+ describe '#in_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].in_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].in_all([[1,2], [3,4]])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) AND "users"."id" IN (3, 4))
+ }
+ end
+ end
+
+ describe '#not_in' do
+ it 'can be constructed with a list' do
+ end
+
+ it 'should return a NotIn node' do
+ attribute = Attribute.new nil, nil, nil
+ node = Nodes::NotIn.new attribute, [1,2,3]
+ check node.left.must_equal attribute
+ check node.right.must_equal [1, 2, 3]
+ end
+
+ it 'should generate NOT IN in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_in([1,2,3])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE "users"."id" NOT IN (1, 2, 3)
+ }
+ end
+ end
+
+ describe '#not_in_any' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].not_in_any([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ORs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_in_any([[1,2], [3,4]])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" NOT IN (1, 2) OR "users"."id" NOT IN (3, 4))
+ }
+ end
+ end
+
+ describe '#not_in_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].not_in_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].not_in_all([[1,2], [3,4]])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" NOT IN (1, 2) AND "users"."id" NOT IN (3, 4))
+ }
+ end
+ end
+
+ describe '#eq_all' do
+ it 'should create a Grouping node' do
+ relation = Table.new(:users)
+ relation[:id].eq_all([1,2]).must_be_kind_of Nodes::Grouping
+ end
+
+ it 'should generate ANDs in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:id].eq_all([1,2])
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2)
+ }
+ end
+ end
+
+ describe '#asc' do
+ it 'should create an Ordering node' do
+ relation = Table.new(:users)
+ relation[:id].asc.must_be_kind_of Nodes::Ordering
+ end
+
+ it 'should generate ASC in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.order relation[:id].asc
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" ORDER BY "users"."id" ASC
+ }
+ end
+ end
+
+ describe '#desc' do
+ it 'should create an Ordering node' do
+ relation = Table.new(:users)
+ relation[:id].desc.must_be_kind_of Nodes::Ordering
+ end
+
+ it 'should generate DESC in sql' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.order relation[:id].desc
+ mgr.to_sql.must_be_like %{
+ SELECT "users"."id" FROM "users" ORDER BY "users"."id" DESC
+ }
+ end
+ end
+ end
+
+ describe 'equality' do
+ describe '#to_sql' do
+ it 'should produce sql' do
+ table = Table.new :users
+ condition = table['id'].eq 1
+ condition.to_sql.must_equal '"users"."id" = 1'
+ end
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb
new file mode 100644
index 0000000000..d65df03313
--- /dev/null
+++ b/test/nodes/test_count.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Arel::Nodes::Count do
+ describe 'backwards compatibility' do
+ it 'must be an expression' do
+ Arel::Nodes::Count.new('foo').must_be_kind_of Arel::Expression
+ end
+ end
+
+ describe "as" do
+ it 'should alias the count' do
+ table = Arel::Table.new :users
+ table[:id].count.as('foo').to_sql.must_be_like %{
+ COUNT("users"."id") AS foo
+ }
+ end
+ end
+end
diff --git a/test/nodes/test_delete_statement.rb b/test/nodes/test_delete_statement.rb
new file mode 100644
index 0000000000..a71da7adae
--- /dev/null
+++ b/test/nodes/test_delete_statement.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Arel::Nodes::DeleteStatement do
+ describe "#clone" do
+ it "clones wheres" do
+ statement = Arel::Nodes::DeleteStatement.new
+ statement.wheres = %w[a b c]
+
+ dolly = statement.clone
+ dolly.wheres.must_equal statement.wheres
+ dolly.wheres.wont_be_same_as statement.wheres
+ end
+ end
+end
diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb
new file mode 100644
index 0000000000..513cafd87f
--- /dev/null
+++ b/test/nodes/test_equality.rb
@@ -0,0 +1,74 @@
+require 'spec_helper'
+
+module Arel
+ module Nodes
+ describe 'equality' do
+ # FIXME: backwards compat
+ describe 'backwards compat' do
+ describe 'operator' do
+ it 'returns :==' do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ check left.operator.must_equal :==
+ end
+ end
+
+ describe 'operand1' do
+ it "should equal left" do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ check left.left.must_equal left.operand1
+ end
+ end
+
+ describe 'operand2' do
+ it "should equal right" do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ check left.right.must_equal left.operand2
+ end
+ end
+
+ describe 'to_sql' do
+ it 'takes an engine' do
+ engine = FakeRecord::Base.new
+ engine.connection.extend Module.new {
+ attr_accessor :quote_count
+ def quote(*args) @quote_count += 1; super; end
+ def quote_column_name(*args) @quote_count += 1; super; end
+ def quote_table_name(*args) @quote_count += 1; super; end
+ }
+ engine.connection.quote_count = 0
+
+ attr = Table.new(:users)[:id]
+ test = attr.eq(10)
+ test.to_sql engine
+ check engine.connection.quote_count.must_equal 2
+ end
+ end
+ end
+
+ describe 'or' do
+ it 'makes an OR node' do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ right = attr.eq(11)
+ node = left.or right
+ check node.expr.left.must_equal left
+ check node.expr.right.must_equal right
+ end
+ end
+
+ describe 'and' do
+ it 'makes and AND node' do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ right = attr.eq(11)
+ node = left.and right
+ check node.left.must_equal left
+ check node.right.must_equal right
+ end
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_insert_statement.rb b/test/nodes/test_insert_statement.rb
new file mode 100644
index 0000000000..47f3c27dee
--- /dev/null
+++ b/test/nodes/test_insert_statement.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Arel::Nodes::InsertStatement do
+ describe "#clone" do
+ it "clones columns and values" do
+ statement = Arel::Nodes::InsertStatement.new
+ statement.columns = %w[a b c]
+ statement.values = %w[x y z]
+
+ dolly = statement.clone
+ dolly.columns.must_equal statement.columns
+ dolly.values.must_equal statement.values
+
+ dolly.columns.wont_be_same_as statement.columns
+ dolly.values.wont_be_same_as statement.values
+ end
+ end
+end
diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb
new file mode 100644
index 0000000000..354d803110
--- /dev/null
+++ b/test/nodes/test_or.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+module Arel
+ module Nodes
+ describe 'or' do
+ describe '#or' do
+ it 'makes an OR node' do
+ attr = Table.new(:users)[:id]
+ left = attr.eq(10)
+ right = attr.eq(11)
+ node = left.or right
+ check node.expr.left.must_equal left
+ check node.expr.right.must_equal right
+
+ oror = node.or(right)
+ check oror.expr.left.must_equal node
+ check oror.expr.right.must_equal right
+ end
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb
new file mode 100644
index 0000000000..0aacf41720
--- /dev/null
+++ b/test/nodes/test_select_core.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Arel::Nodes::SelectCore do
+ describe "#clone" do
+ it "clones froms, projections and wheres" do
+ core = Arel::Nodes::SelectCore.new
+ core.froms = %w[a b c]
+ core.projections = %w[d e f]
+ core.wheres = %w[g h i]
+
+ dolly = core.clone
+
+ dolly.froms.must_equal core.froms
+ dolly.projections.must_equal core.projections
+ dolly.wheres.must_equal core.wheres
+
+ dolly.froms.wont_be_same_as core.froms
+ dolly.projections.wont_be_same_as core.projections
+ dolly.wheres.wont_be_same_as core.wheres
+ end
+ end
+end
diff --git a/test/nodes/test_select_statement.rb b/test/nodes/test_select_statement.rb
new file mode 100644
index 0000000000..45613bfa4d
--- /dev/null
+++ b/test/nodes/test_select_statement.rb
@@ -0,0 +1,13 @@
+require 'spec_helper'
+
+describe Arel::Nodes::SelectStatement do
+ describe "#clone" do
+ it "clones cores" do
+ statement = Arel::Nodes::SelectStatement.new %w[a b c]
+
+ dolly = statement.clone
+ dolly.cores.must_equal statement.cores
+ dolly.cores.wont_be_same_as statement.cores
+ end
+ end
+end
diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb
new file mode 100644
index 0000000000..3aeab41f0c
--- /dev/null
+++ b/test/nodes/test_sql_literal.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+module Arel
+ module Nodes
+ describe 'sql literal' do
+ describe 'sql' do
+ it 'makes a sql literal node' do
+ sql = Arel.sql 'foo'
+ sql.must_be_kind_of Arel::Nodes::SqlLiteral
+ end
+ end
+
+ describe 'count' do
+ it 'makes a count node' do
+ node = SqlLiteral.new('*').count
+ viz = Visitors::ToSql.new Table.engine
+ viz.accept(node).must_be_like %{ COUNT(*) }
+ end
+
+ it 'makes a distinct node' do
+ node = SqlLiteral.new('*').count true
+ viz = Visitors::ToSql.new Table.engine
+ viz.accept(node).must_be_like %{ COUNT(DISTINCT *) }
+ end
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb
new file mode 100644
index 0000000000..e6a57e4dd6
--- /dev/null
+++ b/test/nodes/test_sum.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Arel::Nodes::Sum do
+ describe "as" do
+ it 'should alias the sum' do
+ table = Arel::Table.new :users
+ table[:id].sum.as('foo').to_sql.must_be_like %{
+ SUM("users"."id") AS foo
+ }
+ end
+ end
+end
diff --git a/test/nodes/test_update_statement.rb b/test/nodes/test_update_statement.rb
new file mode 100644
index 0000000000..88c147b268
--- /dev/null
+++ b/test/nodes/test_update_statement.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Arel::Nodes::UpdateStatement do
+ describe "#clone" do
+ it "clones wheres and values" do
+ statement = Arel::Nodes::UpdateStatement.new
+ statement.wheres = %w[a b c]
+ statement.values = %w[x y z]
+
+ dolly = statement.clone
+ dolly.wheres.must_equal statement.wheres
+ dolly.wheres.wont_be_same_as statement.wheres
+
+ dolly.values.must_equal statement.values
+ dolly.values.wont_be_same_as statement.values
+ end
+ end
+end
diff --git a/test/spec_helper.rb b/test/spec_helper.rb
new file mode 100644
index 0000000000..dd288e0d0d
--- /dev/null
+++ b/test/spec_helper.rb
@@ -0,0 +1,21 @@
+require 'rubygems'
+require 'minitest/autorun'
+require 'fileutils'
+require 'arel'
+
+require 'support/fake_record'
+Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new)
+
+# HACK require 'support/shared/tree_manager_shared'
+
+class Object
+ def must_be_like other
+ self.gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip
+ end
+
+ # TODO: remove
+ def check truthiness
+ raise "not truthy" unless truthiness
+ end
+end
+
diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb
new file mode 100644
index 0000000000..ef3cc6a291
--- /dev/null
+++ b/test/support/fake_record.rb
@@ -0,0 +1,89 @@
+module FakeRecord
+ class Column < Struct.new(:name, :type)
+ end
+
+ class Connection
+ attr_reader :tables
+
+ def initialize
+ @tables = %w{ users photos developers }
+ @columns = {
+ 'users' => [
+ Column.new('id', :integer),
+ Column.new('name', :string)
+ ]
+ }
+ @primary_keys = {
+ 'users' => 'id'
+ }
+ end
+
+ def primary_key name
+ @primary_keys[name.to_s]
+ end
+
+ def table_exists? name
+ @tables.include? name.to_s
+ end
+
+ def columns name, message = nil
+ @columns[name.to_s]
+ end
+
+ def quote_table_name name
+ "\"#{name.to_s}\""
+ end
+
+ def quote_column_name name
+ "\"#{name.to_s}\""
+ end
+
+ def quote thing, column = nil
+ if column && column.type == :integer
+ return 'NULL' if thing.nil?
+ return thing.to_i
+ end
+
+ case thing
+ when true
+ "'t'"
+ when false
+ "'f'"
+ when nil
+ 'NULL'
+ when Numeric
+ thing
+ else
+ "'#{thing}'"
+ end
+ end
+ end
+
+ class ConnectionPool
+ class Spec < Struct.new(:config)
+ end
+
+ attr_reader :spec, :connection
+
+ def initialize
+ @spec = Spec.new(:adapter => 'sqlite3')
+ @connection = Connection.new
+ end
+
+ def with_connection
+ yield connection
+ end
+ end
+
+ class Base
+ attr_accessor :connection_pool
+
+ def initialize
+ @connection_pool = ConnectionPool.new
+ end
+
+ def connection
+ connection_pool.connection
+ end
+ end
+end
diff --git a/test/test_activerecord_compat.rb b/test/test_activerecord_compat.rb
new file mode 100644
index 0000000000..2f1d7cff12
--- /dev/null
+++ b/test/test_activerecord_compat.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+module Arel
+ describe 'activerecord compatibility' do
+ describe 'select manager' do
+ it 'provides wheres' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.where table[:id].eq 1
+ manager.where table[:name].eq 'Aaron'
+
+ check manager.wheres.map { |x|
+ x.value
+ }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'"
+ end
+ end
+ end
+end
diff --git a/test/test_attributes.rb b/test/test_attributes.rb
new file mode 100644
index 0000000000..4cdb625b17
--- /dev/null
+++ b/test/test_attributes.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+module Arel
+ describe 'Attributes' do
+ describe 'for' do
+ it 'returns the correct constant for strings' do
+ [:string, :text, :binary].each do |type|
+ column = Struct.new(:type).new type
+ Attributes.for(column).must_equal Attributes::String
+ end
+ end
+
+ it 'returns the correct constant for ints' do
+ column = Struct.new(:type).new :integer
+ Attributes.for(column).must_equal Attributes::Integer
+ end
+
+ it 'returns the correct constant for floats' do
+ column = Struct.new(:type).new :float
+ Attributes.for(column).must_equal Attributes::Float
+ end
+
+ it 'returns the correct constant for decimals' do
+ column = Struct.new(:type).new :decimal
+ Attributes.for(column).must_equal Attributes::Decimal
+ end
+
+ it 'returns the correct constant for boolean' do
+ column = Struct.new(:type).new :boolean
+ Attributes.for(column).must_equal Attributes::Boolean
+ end
+
+ it 'returns the correct constant for time' do
+ [:date, :datetime, :timestamp, :time].each do |type|
+ column = Struct.new(:type).new type
+ Attributes.for(column).must_equal Attributes::Time
+ end
+ end
+ end
+ end
+end
diff --git a/test/test_crud.rb b/test/test_crud.rb
new file mode 100644
index 0000000000..2a0ff651e9
--- /dev/null
+++ b/test/test_crud.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+module Arel
+ class FakeCrudder < SelectManager
+ class FakeEngine
+ attr_reader :calls, :connection_pool, :spec, :config
+
+ def initialize
+ @calls = []
+ @connection_pool = self
+ @spec = self
+ @config = { :adapter => 'sqlite3' }
+ end
+
+ def connection; self end
+
+ def method_missing name, *args
+ @calls << [name, args]
+ end
+ end
+
+ include Crud
+
+ attr_reader :engine
+ attr_accessor :ctx
+
+ def initialize engine = FakeEngine.new
+ super
+ end
+ end
+
+ describe 'crud' do
+ describe 'insert' do
+ it 'should call insert on the connection' do
+ table = Table.new :users
+ fc = FakeCrudder.new
+ fc.from table
+ fc.insert [[table[:id], 'foo']]
+ fc.engine.calls.find { |method, _|
+ method == :insert
+ }.wont_be_nil
+ end
+ end
+
+ describe 'update' do
+ it 'should call update on the connection' do
+ table = Table.new :users
+ fc = FakeCrudder.new
+ fc.from table
+ fc.update [[table[:id], 'foo']]
+ fc.engine.calls.find { |method, _|
+ method == :update
+ }.wont_be_nil
+ end
+ end
+
+ describe 'delete' do
+ it 'should call delete on the connection' do
+ table = Table.new :users
+ fc = FakeCrudder.new
+ fc.from table
+ fc.delete
+ fc.engine.calls.find { |method, _|
+ method == :delete
+ }.wont_be_nil
+ end
+ end
+ end
+end
diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb
new file mode 100644
index 0000000000..0a41c4d3fc
--- /dev/null
+++ b/test/test_delete_manager.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+module Arel
+ describe 'delete manager' do
+ describe 'new' do
+ it 'takes an engine' do
+ Arel::DeleteManager.new Table.engine
+ end
+ end
+
+ describe 'from' do
+ it 'uses from' do
+ table = Table.new(:users)
+ dm = Arel::DeleteManager.new Table.engine
+ dm.from table
+ dm.to_sql.must_be_like %{ DELETE FROM "users" }
+ end
+
+ it 'chains' do
+ table = Table.new(:users)
+ dm = Arel::DeleteManager.new Table.engine
+ check dm.from(table).must_equal dm
+ end
+ end
+
+ describe 'where' do
+ it 'uses where values' do
+ table = Table.new(:users)
+ dm = Arel::DeleteManager.new Table.engine
+ dm.from table
+ dm.where table[:id].eq(10)
+ dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10}
+ end
+
+ it 'chains' do
+ table = Table.new(:users)
+ dm = Arel::DeleteManager.new Table.engine
+ check dm.where(table[:id].eq(10)).must_equal dm
+ end
+ end
+
+ # HACK
+ # describe "TreeManager" do
+ # before do
+ # table = Table.new :users
+ # Arel::DeleteManager.new(Table.engine).tap do |manager|
+ # manager.where(table[:id].eq(10))
+ # end
+ # end
+ #
+ # it_should_behave_like "TreeManager"
+ # end
+ end
+end
diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb
new file mode 100644
index 0000000000..97ba4d7f76
--- /dev/null
+++ b/test/test_insert_manager.rb
@@ -0,0 +1,140 @@
+require 'spec_helper'
+
+module Arel
+ describe 'insert manager' do
+ describe 'new' do
+ it 'takes an engine' do
+ Arel::InsertManager.new Table.engine
+ end
+ end
+
+ describe 'insert' do
+ it "inserts false" do
+ table = Table.new(:users)
+ manager = Arel::InsertManager.new Table.engine
+
+ table[:id].column.extend(Module.new { def type; :boolean; end })
+
+ manager.insert [[table[:id], false]]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id") VALUES ('f')
+ }
+ end
+
+ it "inserts null" do
+ table = Table.new(:users)
+ manager = Arel::InsertManager.new Table.engine
+ manager.insert [[table[:id], nil]]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id") VALUES (NULL)
+ }
+ end
+
+ it "inserts time" do
+ table = Table.new(:users)
+ manager = Arel::InsertManager.new Table.engine
+
+ time = Time.now
+ attribute = table[:id]
+ attribute.column.type = :date
+
+ manager.insert [[attribute, time]]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id") VALUES (#{Table.engine.connection.quote time})
+ }
+ end
+
+ it 'takes a list of lists' do
+ table = Table.new(:users)
+ manager = Arel::InsertManager.new Table.engine
+ manager.into table
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
+ }
+ end
+
+ it 'defaults the table' do
+ table = Table.new(:users)
+ manager = Arel::InsertManager.new Table.engine
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
+ }
+ end
+
+ it 'takes an empty list' do
+ manager = Arel::InsertManager.new Table.engine
+ manager.insert []
+ end
+ end
+
+ describe 'into' do
+ it 'takes an engine' do
+ manager = Arel::InsertManager.new Table.engine
+ manager.into(Table.new(:users)).must_equal manager
+ end
+
+ it 'converts to sql' do
+ table = Table.new :users
+ manager = Arel::InsertManager.new Table.engine
+ manager.into table
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users"
+ }
+ end
+ end
+
+ describe 'columns' do
+ it "converts to sql" do
+ table = Table.new :users
+ manager = Arel::InsertManager.new Table.engine
+ manager.into table
+ manager.columns << table[:id]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id")
+ }
+ end
+ end
+
+ describe "values" do
+ it "converts to sql" do
+ table = Table.new :users
+ manager = Arel::InsertManager.new Table.engine
+ manager.into table
+
+ manager.values = Nodes::Values.new [1]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" VALUES (1)
+ }
+ end
+ end
+
+ describe "combo" do
+ it "puts shit together" do
+ table = Table.new :users
+ manager = Arel::InsertManager.new Table.engine
+ manager.into table
+
+ manager.values = Nodes::Values.new [1, 'aaron']
+ manager.columns << table[:id]
+ manager.columns << table[:name]
+ manager.to_sql.must_be_like %{
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
+ }
+ end
+ end
+
+ # HACK
+ # describe "TreeManager" do
+ # subject do
+ # table = Table.new(:users)
+ # Arel::InsertManager.new(Table.engine).tap do |manager|
+ # manager.insert [[table[:id], nil]]
+ # end
+ # end
+ #
+ # it_should_behave_like "TreeManager"
+ # end
+ end
+end
diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb
new file mode 100644
index 0000000000..75d06438c2
--- /dev/null
+++ b/test/test_select_manager.rb
@@ -0,0 +1,593 @@
+require 'spec_helper'
+
+module Arel
+ class EngineProxy
+ attr_reader :executed
+ attr_reader :connection_pool
+ attr_reader :spec
+ attr_reader :config
+
+ def initialize engine
+ @engine = engine
+ @executed = []
+ @connection_pool = self
+ @spec = self
+ @config = { :adapter => 'sqlite3' }
+ end
+
+ def with_connection
+ yield self
+ end
+
+ def connection
+ self
+ end
+
+ def quote_table_name thing; @engine.connection.quote_table_name thing end
+ def quote_column_name thing; @engine.connection.quote_column_name thing end
+ def quote thing, column; @engine.connection.quote thing, column end
+
+ def execute sql, name = nil, *args
+ @executed << sql
+ end
+ alias :update :execute
+ alias :delete :execute
+ alias :insert :execute
+ end
+
+ describe 'select manager' do
+ describe 'backwards compatibility' do
+ describe 'project' do
+ it 'accepts symbols as sql literals' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project :id
+ manager.from table
+ manager.to_sql.must_be_like %{
+ SELECT id FROM "users"
+ }
+ end
+ end
+
+ describe 'order' do
+ it 'accepts symbols' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project SqlLiteral.new '*'
+ manager.from table
+ manager.order :foo
+ manager.to_sql.must_be_like %{
+ SELECT * FROM "users" ORDER BY foo
+ }
+ end
+ end
+
+ describe 'group' do
+ it 'takes a symbol' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.group :foo
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users" GROUP BY foo
+ }
+ end
+ end
+
+ describe 'from' do
+ it 'ignores strings when table of same name exists' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from table
+ manager.from 'users'
+ manager.project table['id']
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM users'
+ end
+ end
+
+ describe '#having' do
+ it 'converts strings to SQLLiterals' do
+ table = Table.new :users
+ mgr = table.from table
+ mgr.having 'foo'
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo }
+ end
+ end
+ end
+
+ describe 'clone' do
+ it 'creates new cores' do
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
+ mgr = table.from table
+ m2 = mgr.clone
+ m2.project "foo"
+ mgr.to_sql.wont_equal m2.to_sql
+ end
+ end
+
+ describe 'initialize' do
+ it 'uses alias in sql' do
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
+ mgr = table.from table
+ mgr.skip 10
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 }
+ end
+ end
+
+ describe 'skip' do
+ it 'should add an offset' do
+ table = Table.new :users
+ mgr = table.from table
+ mgr.skip 10
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
+ end
+
+ it 'should chain' do
+ table = Table.new :users
+ mgr = table.from table
+ mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
+ end
+ end
+
+ describe 'taken' do
+ it 'should return limit' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.take 10
+ check manager.taken.must_equal 10
+ end
+ end
+
+ describe 'insert' do
+ it 'uses the select FROM' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.insert 'VALUES(NULL)'
+
+ engine.executed.last.must_be_like %{
+ INSERT INTO "users" VALUES(NULL)
+ }
+ end
+ end
+
+ describe 'lock' do
+ # This should fail on other databases
+ it 'adds a lock node' do
+ table = Table.new :users
+ mgr = table.from table
+ mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" }
+ end
+ end
+
+ describe 'orders' do
+ it 'returns order clauses' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ order = table[:id]
+ manager.order table[:id]
+ check manager.orders.must_equal [order]
+ end
+ end
+
+ describe 'order' do
+ it 'generates order clauses' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project SqlLiteral.new '*'
+ manager.from table
+ manager.order table[:id]
+ manager.to_sql.must_be_like %{
+ SELECT * FROM "users" ORDER BY "users"."id"
+ }
+ end
+
+ # FIXME: I would like to deprecate this
+ it 'takes *args' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project SqlLiteral.new '*'
+ manager.from table
+ manager.order table[:id], table[:name]
+ manager.to_sql.must_be_like %{
+ SELECT * FROM "users" ORDER BY "users"."id", "users"."name"
+ }
+ end
+
+ it 'chains' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ check manager.order(table[:id]).must_equal manager
+ end
+ end
+
+ describe 'on' do
+ it 'takes two params' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from left
+ manager.join(right).on(predicate, predicate)
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ INNER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id" AND
+ "users"."id" = "users_2"."id"
+ }
+ end
+
+ it 'takes three params' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from left
+ manager.join(right).on(
+ predicate,
+ predicate,
+ left[:name].eq(right[:name])
+ )
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ INNER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id" AND
+ "users"."id" = "users_2"."id" AND
+ "users"."name" = "users_2"."name"
+ }
+ end
+ end
+
+ describe 'join' do
+ it 'responds to join' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from left
+ manager.join(right).on(predicate)
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ INNER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+
+ it 'takes a class' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from left
+ manager.join(right, Nodes::OuterJoin).on(predicate)
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ LEFT OUTER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+
+ it 'noops on nil' do
+ manager = Arel::SelectManager.new Table.engine
+ check manager.join(nil).must_equal manager
+ end
+ end
+
+ describe 'joins' do
+ it 'returns join sql' do
+ table = Table.new :users
+ aliaz = table.alias
+ manager = Arel::SelectManager.new Table.engine
+ manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
+ manager.join_sql.must_be_like %{
+ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"
+ }
+ check manager.joins(manager).must_equal manager.join_sql
+ end
+
+ it 'returns outer join sql' do
+ table = Table.new :users
+ aliaz = table.alias
+ manager = Arel::SelectManager.new Table.engine
+ manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
+ manager.join_sql.must_be_like %{
+ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"
+ }
+ check manager.joins(manager).must_equal manager.join_sql
+ end
+
+ it 'returns string join sql' do
+ table = Table.new :users
+ aliaz = table.alias
+ manager = Arel::SelectManager.new Table.engine
+ manager.from Nodes::StringJoin.new(table, 'hello')
+ manager.join_sql.must_be_like %{ 'hello' }
+ check manager.joins(manager).must_equal manager.join_sql
+ end
+
+ it 'returns nil join sql' do
+ manager = Arel::SelectManager.new Table.engine
+ manager.join_sql.must_be_nil
+ end
+ end
+
+ describe 'order_clauses' do
+ it 'returns order clauses as a list' do
+ table = Table.new :users
+ aliaz = table.alias
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.order table[:id]
+ manager.order_clauses.first.must_be_like %{ "users"."id" }
+ end
+ end
+
+ describe 'group' do
+ it 'takes an attribute' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.group table[:id]
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users" GROUP BY "users"."id"
+ }
+ end
+
+ it 'chains' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ check manager.group(table[:id]).must_equal manager
+ end
+
+ it 'takes multiple args' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.group table[:id], table[:name]
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users" GROUP BY "users"."id", "users"."name"
+ }
+ end
+
+ # FIXME: backwards compat
+ it 'makes strings literals' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.group 'foo'
+ manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
+ end
+ end
+
+ describe 'delete' do
+ it "copies from" do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.delete
+
+ engine.executed.last.must_be_like %{ DELETE FROM "users" }
+ end
+
+ it "copies where" do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.where table[:id].eq 10
+ manager.delete
+
+ engine.executed.last.must_be_like %{
+ DELETE FROM "users" WHERE "users"."id" = 10
+ }
+ end
+ end
+
+ describe 'where_sql' do
+ it 'gives me back the where sql' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.where table[:id].eq 10
+ manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 }
+ end
+
+ it 'returns nil when there are no wheres' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from table
+ manager.where_sql.must_be_nil
+ end
+ end
+
+ describe 'update' do
+ it 'copies limits' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.take 1
+ manager.update(SqlLiteral.new('foo = bar'))
+
+ engine.executed.last.must_be_like %{
+ UPDATE "users" SET foo = bar
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1)
+ }
+ end
+
+ it 'copies order' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.order :foo
+ manager.update(SqlLiteral.new('foo = bar'))
+
+ engine.executed.last.must_be_like %{
+ UPDATE "users" SET foo = bar
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo)
+ }
+ end
+
+ it 'takes a string' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.update(SqlLiteral.new('foo = bar'))
+
+ engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar }
+ end
+
+ it 'copies where clauses' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.where table[:id].eq 10
+ manager.from table
+ manager.update(table[:id] => 1)
+
+ engine.executed.last.must_be_like %{
+ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10
+ }
+ end
+
+ it 'executes an update statement' do
+ engine = EngineProxy.new Table.engine
+ table = Table.new :users
+ manager = Arel::SelectManager.new engine
+ manager.from table
+ manager.update(table[:id] => 1)
+
+ engine.executed.last.must_be_like %{
+ UPDATE "users" SET "id" = 1
+ }
+ end
+ end
+
+ describe 'project' do
+ it 'takes multiple args' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project Nodes::SqlLiteral.new('foo'),
+ Nodes::SqlLiteral.new('bar')
+ manager.to_sql.must_be_like %{ SELECT foo, bar }
+ end
+
+ it 'takes strings' do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project Nodes::SqlLiteral.new('*')
+ manager.to_sql.must_be_like %{ SELECT * }
+ end
+
+ it "takes sql literals" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.project Nodes::SqlLiteral.new '*'
+ manager.to_sql.must_be_like %{
+ SELECT *
+ }
+ end
+ end
+
+ describe 'take' do
+ it "knows take" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from(table).project(table['id'])
+ manager.where(table['id'].eq(1))
+ manager.take 1
+
+ manager.to_sql.must_be_like %{
+ SELECT "users"."id"
+ FROM "users"
+ WHERE "users"."id" = 1
+ LIMIT 1
+ }
+ end
+
+ it "chains" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.take(1).must_equal manager
+ end
+ end
+
+ describe 'where' do
+ it "knows where" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from(table).project(table['id'])
+ manager.where(table['id'].eq(1))
+ manager.to_sql.must_be_like %{
+ SELECT "users"."id"
+ FROM "users"
+ WHERE "users"."id" = 1
+ }
+ end
+
+ it "chains" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ manager.from(table)
+ manager.project(table['id']).where(table['id'].eq 1).must_equal manager
+ end
+ end
+
+ describe "join" do
+ it "joins itself" do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+
+ mgr = left.join(right)
+ mgr.project Nodes::SqlLiteral.new('*')
+ check mgr.on(predicate).must_equal mgr
+
+ mgr.to_sql.must_be_like %{
+ SELECT * FROM "users"
+ INNER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+ end
+
+ describe 'from' do
+ it "makes sql" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+
+ manager.from table
+ manager.project table['id']
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
+ end
+
+ it "chains" do
+ table = Table.new :users
+ manager = Arel::SelectManager.new Table.engine
+ check manager.from(table).project(table['id']).must_equal manager
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
+ end
+ end
+
+ # HACK
+ # describe "TreeManager" do
+ # subject do
+ # table = Table.new :users
+ # Arel::SelectManager.new(Table.engine).tap do |manager|
+ # manager.from(table).project(table['id'])
+ # end
+ # end
+ #
+ # it_should_behave_like "TreeManager"
+ # end
+ end
+end
diff --git a/test/test_table.rb b/test/test_table.rb
new file mode 100644
index 0000000000..ecb5c1eb79
--- /dev/null
+++ b/test/test_table.rb
@@ -0,0 +1,175 @@
+require 'spec_helper'
+
+module Arel
+ describe Table do
+ before do
+ @relation = Table.new(:users)
+ end
+
+ describe 'primary_key' do
+ it 'should return an attribute' do
+ check @relation.primary_key.name.must_equal :id
+ end
+ end
+
+ describe 'select_manager' do
+ it 'should return an empty select manager' do
+ sm = @relation.select_manager
+ sm.to_sql.must_be_like 'SELECT'
+ end
+ end
+
+ describe 'having' do
+ it 'adds a having clause' do
+ mgr = @relation.having @relation[:id].eq(10)
+ mgr.to_sql.must_be_like %{
+ SELECT FROM "users" HAVING "users"."id" = 10
+ }
+ end
+ end
+
+ describe 'backwards compat' do
+ describe 'joins' do
+ it 'returns nil' do
+ check @relation.joins(nil).must_equal nil
+ end
+ end
+
+ describe 'join' do
+ it 'noops on nil' do
+ mgr = @relation.join nil
+
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" }
+ end
+
+ it 'takes a second argument for join type' do
+ right = @relation.alias
+ predicate = @relation[:id].eq(right[:id])
+ mgr = @relation.join(right, Nodes::OuterJoin).on(predicate)
+
+ mgr.to_sql.must_be_like %{
+ SELECT FROM "users"
+ LEFT OUTER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+ end
+ end
+
+ describe 'group' do
+ it 'should create a group' do
+ manager = @relation.group @relation[:id]
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users" GROUP BY "users"."id"
+ }
+ end
+ end
+
+ describe 'alias' do
+ it 'should create a node that proxies to a table' do
+ check @relation.aliases.must_equal []
+
+ node = @relation.alias
+ check @relation.aliases.must_equal [node]
+ check node.name.must_equal 'users_2'
+ check node[:id].relation.must_equal node
+ end
+ end
+
+ describe 'new' do
+ it 'takes :columns' do
+ columns = Table.engine.connection.columns("users")
+ @relation = Table.new(:users, :columns => columns)
+ check @relation.columns.first.name.must_equal :id
+ check @relation.engine.must_equal Table.engine
+ end
+
+ it 'should accept an engine' do
+ rel = Table.new :users, 'foo'
+ check rel.engine.must_equal 'foo'
+ end
+
+ it 'should accept a hash' do
+ rel = Table.new :users, :engine => 'foo'
+ check rel.engine.must_equal 'foo'
+ end
+
+ it 'ignores as if it equals name' do
+ rel = Table.new :users, :as => 'users'
+ rel.table_alias.must_be_nil
+ end
+ end
+
+ describe 'order' do
+ it "should take an order" do
+ manager = @relation.order "foo"
+ manager.to_sql.must_be_like %{ SELECT FROM "users" ORDER BY foo }
+ end
+ end
+
+ describe 'take' do
+ it "should add a limit" do
+ manager = @relation.take 1
+ manager.project SqlLiteral.new '*'
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" LIMIT 1 }
+ end
+ end
+
+ describe 'project' do
+ it 'can project' do
+ manager = @relation.project SqlLiteral.new '*'
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" }
+ end
+
+ it 'takes multiple parameters' do
+ manager = @relation.project SqlLiteral.new('*'), SqlLiteral.new('*')
+ manager.to_sql.must_be_like %{ SELECT *, * FROM "users" }
+ end
+ end
+
+ describe 'where' do
+ it "returns a tree manager" do
+ manager = @relation.where @relation[:id].eq 1
+ manager.project @relation[:id]
+ manager.must_be_kind_of TreeManager
+ manager.to_sql.must_be_like %{
+ SELECT "users"."id"
+ FROM "users"
+ WHERE "users"."id" = 1
+ }
+ end
+ end
+
+ describe 'columns' do
+ it 'returns a list of columns' do
+ columns = @relation.columns
+ check columns.length.must_equal 2
+ columns.map { |x| x.name.to_s }.sort.must_equal %w{ name id }.sort
+ end
+ end
+
+ it "should have a name" do
+ @relation.name.must_equal :users
+ end
+
+ it "should have an engine" do
+ @relation.engine.must_equal Table.engine
+ end
+
+ describe '[]' do
+ describe 'when given a Symbol' do
+ it "manufactures an attribute if the symbol names an attribute within the relation" do
+ column = @relation[:id]
+ check column.name.must_equal :id
+ column.must_be_kind_of Attributes::Integer
+ end
+ end
+
+ describe 'when table does not exist' do
+ it 'returns nil' do
+ @relation[:foooo].must_be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb
new file mode 100644
index 0000000000..670f19d621
--- /dev/null
+++ b/test/test_update_manager.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+module Arel
+ describe 'update manager' do
+ describe 'new' do
+ it 'takes an engine' do
+ Arel::UpdateManager.new Table.engine
+ end
+ end
+
+ describe 'set' do
+ it "updates with null" do
+ table = Table.new(:users)
+ um = Arel::UpdateManager.new Table.engine
+ um.table table
+ um.set [[table[:name], nil]]
+ um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL }
+ end
+
+ it 'takes a string' do
+ table = Table.new(:users)
+ um = Arel::UpdateManager.new Table.engine
+ um.table table
+ um.set Nodes::SqlLiteral.new "foo = bar"
+ um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar }
+ end
+
+ it 'takes a list of lists' do
+ table = Table.new(:users)
+ um = Arel::UpdateManager.new Table.engine
+ um.table table
+ um.set [[table[:id], 1], [table[:name], 'hello']]
+ um.to_sql.must_be_like %{
+ UPDATE "users" SET "id" = 1, "name" = 'hello'
+ }
+ end
+
+ it 'chains' do
+ table = Table.new(:users)
+ um = Arel::UpdateManager.new Table.engine
+ um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um
+ end
+ end
+
+ describe 'table' do
+ it 'generates an update statement' do
+ um = Arel::UpdateManager.new Table.engine
+ um.table Table.new(:users)
+ um.to_sql.must_be_like %{ UPDATE "users" }
+ end
+
+ it 'chains' do
+ um = Arel::UpdateManager.new Table.engine
+ um.table(Table.new(:users)).must_equal um
+ end
+ end
+
+ describe 'where' do
+ it 'generates a where clause' do
+ table = Table.new :users
+ um = Arel::UpdateManager.new Table.engine
+ um.table table
+ um.where table[:id].eq(1)
+ um.to_sql.must_be_like %{
+ UPDATE "users" WHERE "users"."id" = 1
+ }
+ end
+
+ it 'chains' do
+ table = Table.new :users
+ um = Arel::UpdateManager.new Table.engine
+ um.table table
+ um.where(table[:id].eq(1)).must_equal um
+ end
+ end
+
+ # HACK
+ # describe "TreeManager" do
+ # subject do
+ # table = Table.new :users
+ # Arel::UpdateManager.new(Table.engine).tap do |manager|
+ # manager.table table
+ # manager.where table[:id].eq(1)
+ # end
+ # end
+ #
+ # it_should_behave_like "TreeManager"
+ # end
+ end
+end
diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb
new file mode 100644
index 0000000000..3dc70d7dd6
--- /dev/null
+++ b/test/visitors/test_join_sql.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+module Arel
+ module Visitors
+ describe 'the join_sql visitor' do
+ before do
+ @visitor = JoinSql.new Table.engine
+ end
+
+ describe 'inner join' do
+ it 'should visit left if left is a join' do
+ t = Table.new :users
+ join = Nodes::InnerJoin.new t, t, Nodes::On.new(t[:id])
+ j2 = Nodes::InnerJoin.new join, t, Nodes::On.new(t[:id])
+ @visitor.accept(j2).must_be_like %{
+ INNER JOIN "users" ON "users"."id"
+ INNER JOIN "users" ON "users"."id"
+ }
+ end
+ end
+
+ describe 'outer join' do
+ it 'should visit left if left is a join' do
+ t = Table.new :users
+ join = Nodes::OuterJoin.new t, t, Nodes::On.new(t[:id])
+ j2 = Nodes::OuterJoin.new join, t, Nodes::On.new(t[:id])
+ @visitor.accept(j2).must_be_like %{
+ LEFT OUTER JOIN "users" ON "users"."id"
+ LEFT OUTER JOIN "users" ON "users"."id"
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb
new file mode 100644
index 0000000000..8b5732f287
--- /dev/null
+++ b/test/visitors/test_oracle.rb
@@ -0,0 +1,111 @@
+require 'spec_helper'
+
+module Arel
+ module Visitors
+ describe 'the oracle visitor' do
+ before do
+ @visitor = Oracle.new Table.engine
+ end
+
+ it 'modifies order when there is distinct and first value' do
+ # *sigh*
+ select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
+ stmt = Nodes::SelectStatement.new
+ stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
+ stmt.orders << Nodes::SqlLiteral.new('foo')
+ sql = @visitor.accept(stmt)
+ sql.must_be_like %{
+ SELECT #{select} ORDER BY alias_0__
+ }
+ end
+
+ it 'is idempotent with crazy query' do
+ # *sigh*
+ select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
+ stmt = Nodes::SelectStatement.new
+ stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
+ stmt.orders << Nodes::SqlLiteral.new('foo')
+
+ sql = @visitor.accept(stmt)
+ sql2 = @visitor.accept(stmt)
+ check sql.must_equal sql2
+ end
+
+ it 'splits orders with commas' do
+ # *sigh*
+ select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
+ stmt = Nodes::SelectStatement.new
+ stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
+ stmt.orders << Nodes::SqlLiteral.new('foo, bar')
+ sql = @visitor.accept(stmt)
+ sql.must_be_like %{
+ SELECT #{select} ORDER BY alias_0__, alias_1__
+ }
+ end
+
+ describe 'Nodes::SelectStatement' do
+ describe 'limit' do
+ it 'adds a rownum clause' do
+ stmt = Nodes::SelectStatement.new
+ stmt.limit = 10
+ sql = @visitor.accept stmt
+ sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 }
+ end
+
+ it 'is idempotent' do
+ stmt = Nodes::SelectStatement.new
+ stmt.orders << Nodes::SqlLiteral.new('foo')
+ stmt.limit = 10
+ sql = @visitor.accept stmt
+ sql2 = @visitor.accept stmt
+ check sql.must_equal sql2
+ end
+
+ it 'creates a subquery when there is order_by' do
+ stmt = Nodes::SelectStatement.new
+ stmt.orders << Nodes::SqlLiteral.new('foo')
+ stmt.limit = 10
+ sql = @visitor.accept stmt
+ sql.must_be_like %{
+ SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10
+ }
+ end
+
+ it 'creates a subquery when there is DISTINCT' do
+ stmt = Nodes::SelectStatement.new
+ stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id')
+ stmt.limit = 10
+ sql = @visitor.accept stmt
+ sql.must_be_like %{
+ SELECT * FROM (SELECT DISTINCT id) WHERE ROWNUM <= 10
+ }
+ end
+
+ it 'creates a different subquery when there is an offset' do
+ stmt = Nodes::SelectStatement.new
+ stmt.limit = 10
+ stmt.offset = Nodes::Offset.new(10)
+ sql = @visitor.accept stmt
+ sql.must_be_like %{
+ SELECT * FROM (
+ SELECT raw_sql_.*, rownum raw_rnum_
+ FROM (SELECT ) raw_sql_
+ WHERE rownum <= 20
+ )
+ WHERE raw_rnum_ > 10
+ }
+ end
+
+ it 'is idempotent with different subquery' do
+ stmt = Nodes::SelectStatement.new
+ stmt.limit = 10
+ stmt.offset = Nodes::Offset.new(10)
+ sql = @visitor.accept stmt
+ sql2 = @visitor.accept stmt
+ check sql.must_equal sql2
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb
new file mode 100644
index 0000000000..70b935c185
--- /dev/null
+++ b/test/visitors/test_postgres.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+module Arel
+ module Visitors
+ describe 'the postgres visitor' do
+ before do
+ @visitor = PostgreSQL.new Table.engine
+ end
+
+ it 'should produce a lock value' do
+ @visitor.accept(Nodes::Lock.new).must_be_like %{
+ FOR UPDATE
+ }
+ end
+ end
+ end
+end
diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb
new file mode 100644
index 0000000000..f7455d7fa3
--- /dev/null
+++ b/test/visitors/test_to_sql.rb
@@ -0,0 +1,134 @@
+require 'spec_helper'
+
+module Arel
+ module Visitors
+ describe 'the to_sql visitor' do
+ before do
+ @visitor = ToSql.new Table.engine
+ @attr = Table.new(:users)[:id]
+ end
+
+ describe 'equality' do
+ it 'should handle false' do
+ sql = @visitor.accept Nodes::Equality.new(false, false)
+ sql.must_be_like %{ 'f' = 'f' }
+ end
+
+ it 'should use the column to quote' do
+ table = Table.new(:users)
+ sql = @visitor.accept Nodes::Equality.new(table[:id], '1-fooo')
+ sql.must_be_like %{ "users"."id" = 1 }
+ end
+ end
+
+ it "should visit_DateTime" do
+ @visitor.accept DateTime.now
+ end
+
+ it "should visit_Float" do
+ @visitor.accept 2.14
+ end
+
+ it "should visit_Hash" do
+ @visitor.accept({:a => 1})
+ end
+
+ it "should visit_BigDecimal" do
+ @visitor.accept BigDecimal.new('2.14')
+ end
+
+ it "should visit_Date" do
+ @visitor.accept Date.today
+ end
+
+ it "should visit_Arel_Nodes_And" do
+ node = Nodes::And.new @attr.eq(10), @attr.eq(11)
+ @visitor.accept(node).must_be_like %{
+ "users"."id" = 10 AND "users"."id" = 11
+ }
+ end
+
+ it "should visit_Arel_Nodes_Or" do
+ node = Nodes::Or.new @attr.eq(10), @attr.eq(11)
+ @visitor.accept(node).must_be_like %{
+ "users"."id" = 10 OR "users"."id" = 11
+ }
+ end
+
+ it "should visit visit_Arel_Attributes_Time" do
+ attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column)
+ @visitor.accept attr
+ end
+
+ it "should visit_TrueClass" do
+ test = @attr.eq(true)
+ test.left.column.type = :boolean
+ @visitor.accept(test).must_be_like %{ "users"."id" = 't' }
+ end
+
+ describe "Nodes::Ordering" do
+ it "should know how to visit" do
+ node = @attr.desc
+ @visitor.accept(node).must_be_like %{
+ "users"."id" DESC
+ }
+ end
+ end
+
+ describe "Nodes::In" do
+ it "should know how to visit" do
+ node = @attr.in [1, 2, 3]
+ @visitor.accept(node).must_be_like %{
+ "users"."id" IN (1, 2, 3)
+ }
+ end
+
+ it "should turn empty right to NULL" do
+ node = @attr.in []
+ @visitor.accept(node).must_be_like %{
+ "users"."id" IN (NULL)
+ }
+ end
+
+ it 'can handle two dot ranges' do
+ node = @attr.in 1..3
+ @visitor.accept(node).must_be_like %{
+ "users"."id" BETWEEN 1 AND 3
+ }
+ end
+
+ it 'can handle three dot ranges' do
+ node = @attr.in 1...3
+ @visitor.accept(node).must_be_like %{
+ "users"."id" >= 1 AND "users"."id" < 3
+ }
+ end
+
+ it 'uses the same column for escaping values' do
+ visitor = Class.new(ToSql) do
+ attr_accessor :expected
+
+ def quote value, column = nil
+ raise unless column == expected
+ super
+ end
+ end
+ in_node = Nodes::In.new @attr, %w{ a b c }
+ visitor = visitor.new(Table.engine)
+ visitor.expected = @attr.column
+ visitor.accept(in_node).must_equal %("users"."id" IN ('a', 'b', 'c'))
+ end
+ end
+
+ describe 'Equality' do
+ it "should escape strings" do
+ test = @attr.eq 'Aaron Patterson'
+ test.left.column.type = :string
+ @visitor.accept(test).must_be_like %{
+ "users"."id" = 'Aaron Patterson'
+ }
+ end
+ end
+ end
+ end
+end