arel 2.0.10 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/History.txt +51 -4
  2. data/Manifest.txt +15 -31
  3. data/README.markdown +27 -3
  4. data/Rakefile +0 -2
  5. data/arel.gemspec +20 -19
  6. data/lib/arel.rb +9 -1
  7. data/lib/arel/alias_predication.rb +7 -0
  8. data/lib/arel/attributes/attribute.rb +10 -1
  9. data/lib/arel/crud.rb +43 -8
  10. data/lib/arel/expression.rb +1 -0
  11. data/lib/arel/factory_methods.rb +35 -0
  12. data/lib/arel/insert_manager.rb +5 -1
  13. data/lib/arel/math.rb +19 -0
  14. data/lib/arel/nodes.rb +32 -42
  15. data/lib/arel/nodes/and.rb +18 -1
  16. data/lib/arel/nodes/binary.rb +28 -0
  17. data/lib/arel/nodes/count.rb +0 -3
  18. data/lib/arel/nodes/function.rb +13 -2
  19. data/lib/arel/nodes/infix_operation.rb +43 -0
  20. data/lib/arel/nodes/join_source.rb +14 -0
  21. data/lib/arel/nodes/named_function.rb +14 -0
  22. data/lib/arel/nodes/node.rb +5 -2
  23. data/lib/arel/nodes/select_core.rb +24 -10
  24. data/lib/arel/nodes/select_statement.rb +8 -6
  25. data/lib/arel/nodes/sql_literal.rb +2 -0
  26. data/lib/arel/nodes/string_join.rb +2 -4
  27. data/lib/arel/nodes/table_alias.rb +7 -3
  28. data/lib/arel/nodes/{as.rb → terminal.rb} +1 -1
  29. data/lib/arel/nodes/unary.rb +17 -0
  30. data/lib/arel/nodes/unqualified_column.rb +4 -0
  31. data/lib/arel/nodes/update_statement.rb +4 -2
  32. data/lib/arel/nodes/with.rb +10 -0
  33. data/lib/arel/order_predications.rb +13 -0
  34. data/lib/arel/predications.rb +6 -24
  35. data/lib/arel/select_manager.rb +95 -40
  36. data/lib/arel/table.rb +32 -19
  37. data/lib/arel/tree_manager.rb +1 -0
  38. data/lib/arel/update_manager.rb +4 -0
  39. data/lib/arel/visitors.rb +2 -0
  40. data/lib/arel/visitors/depth_first.rb +19 -9
  41. data/lib/arel/visitors/dot.rb +42 -25
  42. data/lib/arel/visitors/ibm_db.rb +12 -0
  43. data/lib/arel/visitors/join_sql.rb +2 -23
  44. data/lib/arel/visitors/mssql.rb +7 -0
  45. data/lib/arel/visitors/mysql.rb +4 -0
  46. data/lib/arel/visitors/oracle.rb +2 -2
  47. data/lib/arel/visitors/postgresql.rb +2 -38
  48. data/lib/arel/visitors/to_sql.rb +148 -67
  49. data/test/attributes/test_attribute.rb +3 -3
  50. data/test/helper.rb +1 -1
  51. data/test/nodes/test_as.rb +6 -0
  52. data/test/nodes/test_bin.rb +23 -0
  53. data/test/nodes/test_named_function.rb +30 -0
  54. data/test/nodes/test_node.rb +10 -0
  55. data/test/nodes/test_not.rb +4 -7
  56. data/test/nodes/test_select_core.rb +23 -14
  57. data/test/support/fake_record.rb +21 -4
  58. data/test/test_attributes.rb +8 -0
  59. data/test/test_crud.rb +6 -12
  60. data/test/test_factory_methods.rb +34 -0
  61. data/test/test_insert_manager.rb +19 -0
  62. data/test/test_select_manager.rb +343 -64
  63. data/test/test_table.rb +36 -45
  64. data/test/visitors/test_depth_first.rb +29 -11
  65. data/test/visitors/test_dot.rb +47 -0
  66. data/test/visitors/test_ibm_db.rb +27 -0
  67. data/test/visitors/test_join_sql.rb +14 -7
  68. data/test/visitors/test_mssql.rb +9 -0
  69. data/test/visitors/test_oracle.rb +11 -10
  70. data/test/visitors/test_postgres.rb +12 -0
  71. data/test/visitors/test_to_sql.rb +80 -17
  72. metadata +80 -101
  73. data/lib/arel/nodes/assignment.rb +0 -6
  74. data/lib/arel/nodes/avg.rb +0 -6
  75. data/lib/arel/nodes/between.rb +0 -6
  76. data/lib/arel/nodes/does_not_match.rb +0 -6
  77. data/lib/arel/nodes/except.rb +0 -7
  78. data/lib/arel/nodes/exists.rb +0 -7
  79. data/lib/arel/nodes/greater_than.rb +0 -6
  80. data/lib/arel/nodes/greater_than_or_equal.rb +0 -6
  81. data/lib/arel/nodes/group.rb +0 -6
  82. data/lib/arel/nodes/grouping.rb +0 -6
  83. data/lib/arel/nodes/having.rb +0 -6
  84. data/lib/arel/nodes/intersect.rb +0 -7
  85. data/lib/arel/nodes/join.rb +0 -13
  86. data/lib/arel/nodes/less_than.rb +0 -6
  87. data/lib/arel/nodes/less_than_or_equal.rb +0 -6
  88. data/lib/arel/nodes/limit.rb +0 -7
  89. data/lib/arel/nodes/lock.rb +0 -6
  90. data/lib/arel/nodes/matches.rb +0 -6
  91. data/lib/arel/nodes/max.rb +0 -6
  92. data/lib/arel/nodes/min.rb +0 -6
  93. data/lib/arel/nodes/not.rb +0 -6
  94. data/lib/arel/nodes/not_equal.rb +0 -6
  95. data/lib/arel/nodes/not_in.rb +0 -6
  96. data/lib/arel/nodes/offset.rb +0 -7
  97. data/lib/arel/nodes/on.rb +0 -6
  98. data/lib/arel/nodes/or.rb +0 -6
  99. data/lib/arel/nodes/sum.rb +0 -6
  100. data/lib/arel/nodes/top.rb +0 -6
  101. data/lib/arel/nodes/union.rb +0 -7
  102. data/lib/arel/nodes/union_all.rb +0 -7
@@ -6,6 +6,38 @@ module Arel
6
6
  @relation = Table.new(:users)
7
7
  end
8
8
 
9
+ it 'should create join nodes' do
10
+ join = @relation.create_string_join 'foo'
11
+ assert_kind_of Arel::Nodes::StringJoin, join
12
+ assert_equal 'foo', join.left
13
+ end
14
+
15
+ it 'should create join nodes' do
16
+ join = @relation.create_join 'foo', 'bar'
17
+ assert_kind_of Arel::Nodes::InnerJoin, join
18
+ assert_equal 'foo', join.left
19
+ assert_equal 'bar', join.right
20
+ end
21
+
22
+ it 'should create join nodes with a klass' do
23
+ join = @relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin
24
+ assert_kind_of Arel::Nodes::OuterJoin, join
25
+ assert_equal 'foo', join.left
26
+ assert_equal 'bar', join.right
27
+ end
28
+
29
+ it 'should return an insert manager' do
30
+ im = @relation.compile_insert 'VALUES(NULL)'
31
+ assert_kind_of Arel::InsertManager, im
32
+ assert_equal 'INSERT INTO NULL VALUES(NULL)', im.to_sql
33
+ end
34
+
35
+ it 'should return IM from insert_manager' do
36
+ im = @relation.insert_manager
37
+ assert_kind_of Arel::InsertManager, im
38
+ assert_equal im.engine, @relation.engine
39
+ end
40
+
9
41
  describe 'skip' do
10
42
  it 'should add an offset' do
11
43
  sm = @relation.skip 2
@@ -13,12 +45,6 @@ module Arel
13
45
  end
14
46
  end
15
47
 
16
- describe 'primary_key' do
17
- it 'should return an attribute' do
18
- @relation.primary_key.name.must_equal :id
19
- end
20
- end
21
-
22
48
  describe 'select_manager' do
23
49
  it 'should return an empty select manager' do
24
50
  sm = @relation.select_manager
@@ -36,12 +62,6 @@ module Arel
36
62
  end
37
63
 
38
64
  describe 'backwards compat' do
39
- describe 'joins' do
40
- it 'returns nil' do
41
- @relation.joins(nil).must_equal nil
42
- end
43
- end
44
-
45
65
  describe 'join' do
46
66
  it 'noops on nil' do
47
67
  mgr = @relation.join nil
@@ -84,13 +104,6 @@ module Arel
84
104
  end
85
105
 
86
106
  describe 'new' do
87
- it 'takes :columns' do
88
- columns = Table.engine.connection.columns("users")
89
- @relation = Table.new(:users, :columns => columns)
90
- @relation.columns.first.name.must_equal :id
91
- @relation.engine.must_equal Table.engine
92
- end
93
-
94
107
  it 'should accept an engine' do
95
108
  rel = Table.new :users, 'foo'
96
109
  rel.engine.must_equal 'foo'
@@ -147,18 +160,14 @@ module Arel
147
160
  end
148
161
  end
149
162
 
150
- describe 'columns' do
151
- it 'returns a list of columns' do
152
- columns = @relation.columns
153
- columns.length.must_equal 4
154
- columns.map { |x| x.name.to_s }.sort.must_equal %w{ created_at bool name id }.sort
155
- end
156
- end
157
-
158
163
  it "should have a name" do
159
164
  @relation.name.must_equal 'users'
160
165
  end
161
166
 
167
+ it "should have a table name" do
168
+ @relation.table_name.must_equal 'users'
169
+ end
170
+
162
171
  it "should have an engine" do
163
172
  @relation.engine.must_equal Table.engine
164
173
  end
@@ -168,24 +177,6 @@ module Arel
168
177
  it "manufactures an attribute if the symbol names an attribute within the relation" do
169
178
  column = @relation[:id]
170
179
  column.name.must_equal :id
171
- column.must_be_kind_of Attributes::Integer
172
- end
173
- end
174
-
175
- describe 'when table does not exist' do
176
- it 'returns nil' do
177
- @relation[:foooo].must_be_nil
178
- end
179
- end
180
- end
181
- end
182
-
183
- describe Table do
184
- describe 'when checking the existence of a table' do
185
- it 'should be present in the table cache despite the class of its name' do
186
- [ 'users', :users ].each do |name|
187
- relation = Table.new name
188
- Table.table_cache(relation.engine).key?(relation.name).must_equal true
189
180
  end
190
181
  end
191
182
  end
@@ -29,6 +29,7 @@ module Arel
29
29
  Arel::Nodes::Grouping,
30
30
  Arel::Nodes::Offset,
31
31
  Arel::Nodes::Having,
32
+ Arel::Nodes::StringJoin,
32
33
  Arel::Nodes::UnqualifiedColumn,
33
34
  Arel::Nodes::Top,
34
35
  Arel::Nodes::Limit,
@@ -49,12 +50,18 @@ module Arel
49
50
  Arel::Nodes::Sum,
50
51
  ].each do |klass|
51
52
  define_method("test_#{klass.name.gsub('::', '_')}") do
52
- func = klass.new(:a, :b)
53
+ func = klass.new(:a, "b")
53
54
  @visitor.accept func
54
- assert_equal [:a, :b, func], @collector.calls
55
+ assert_equal [:a, "b", false, func], @collector.calls
55
56
  end
56
57
  end
57
58
 
59
+ def test_named_function
60
+ func = Arel::Nodes::NamedFunction.new(:a, :b, "c")
61
+ @visitor.accept func
62
+ assert_equal [:a, :b, false, "c", func], @collector.calls
63
+ end
64
+
58
65
  def test_lock
59
66
  lock = Nodes::Lock.new true
60
67
  @visitor.accept lock
@@ -62,25 +69,24 @@ module Arel
62
69
  end
63
70
 
64
71
  def test_count
65
- count = Nodes::Count.new :a, :b, :c
72
+ count = Nodes::Count.new :a, :b, "c"
66
73
  @visitor.accept count
67
- assert_equal [:a, :c, :b, count], @collector.calls
74
+ assert_equal [:a, "c", :b, count], @collector.calls
68
75
  end
69
76
 
70
77
  def test_inner_join
71
- join = Nodes::InnerJoin.new :a, :b, :c
78
+ join = Nodes::InnerJoin.new :a, :b
72
79
  @visitor.accept join
73
- assert_equal [:a, :b, :c, join], @collector.calls
80
+ assert_equal [:a, :b, join], @collector.calls
74
81
  end
75
82
 
76
83
  def test_outer_join
77
- join = Nodes::OuterJoin.new :a, :b, :c
84
+ join = Nodes::OuterJoin.new :a, :b
78
85
  @visitor.accept join
79
- assert_equal [:a, :b, :c, join], @collector.calls
86
+ assert_equal [:a, :b, join], @collector.calls
80
87
  end
81
88
 
82
89
  [
83
- Arel::Nodes::And,
84
90
  Arel::Nodes::Assignment,
85
91
  Arel::Nodes::Between,
86
92
  Arel::Nodes::DoesNotMatch,
@@ -94,12 +100,12 @@ module Arel
94
100
  Arel::Nodes::NotEqual,
95
101
  Arel::Nodes::NotIn,
96
102
  Arel::Nodes::Or,
97
- Arel::Nodes::StringJoin,
98
103
  Arel::Nodes::TableAlias,
99
104
  Arel::Nodes::Values,
100
105
  Arel::Nodes::As,
101
106
  Arel::Nodes::DeleteStatement,
102
107
  Arel::Nodes::Ordering,
108
+ Arel::Nodes::JoinSource,
103
109
  ].each do |klass|
104
110
  define_method("test_#{klass.name.gsub('::', '_')}") do
105
111
  binary = klass.new(:a, :b)
@@ -108,6 +114,17 @@ module Arel
108
114
  end
109
115
  end
110
116
 
117
+ # N-ary
118
+ [
119
+ Arel::Nodes::And,
120
+ ].each do |klass|
121
+ define_method("test_#{klass.name.gsub('::', '_')}") do
122
+ binary = klass.new([:a, :b, :c])
123
+ @visitor.accept binary
124
+ assert_equal [:a, :b, :c, binary], @collector.calls
125
+ end
126
+ end
127
+
111
128
  [
112
129
  Arel::Attributes::Integer,
113
130
  Arel::Attributes::Float,
@@ -167,7 +184,8 @@ module Arel
167
184
  @visitor.accept core
168
185
  assert_equal [
169
186
  :a, core.projections,
170
- :b,
187
+ :b, [],
188
+ core.source,
171
189
  :c, core.wheres,
172
190
  :d, core.groups,
173
191
  :e,
@@ -7,6 +7,25 @@ module Arel
7
7
  @visitor = Visitors::Dot.new
8
8
  end
9
9
 
10
+ # functions
11
+ [
12
+ Nodes::Sum,
13
+ Nodes::Exists,
14
+ Nodes::Max,
15
+ Nodes::Min,
16
+ Nodes::Avg,
17
+ ].each do |klass|
18
+ define_method("test_#{klass.name.gsub('::', '_')}") do
19
+ op = klass.new(:a, "z")
20
+ @visitor.accept op
21
+ end
22
+ end
23
+
24
+ def test_named_function
25
+ func = Nodes::NamedFunction.new 'omg', 'omg'
26
+ @visitor.accept func
27
+ end
28
+
10
29
  # unary ops
11
30
  [
12
31
  Arel::Nodes::Not,
@@ -24,6 +43,34 @@ module Arel
24
43
  @visitor.accept op
25
44
  end
26
45
  end
46
+
47
+ # binary ops
48
+ [
49
+ Arel::Nodes::Assignment,
50
+ Arel::Nodes::Between,
51
+ Arel::Nodes::DoesNotMatch,
52
+ Arel::Nodes::Equality,
53
+ Arel::Nodes::GreaterThan,
54
+ Arel::Nodes::GreaterThanOrEqual,
55
+ Arel::Nodes::In,
56
+ Arel::Nodes::LessThan,
57
+ Arel::Nodes::LessThanOrEqual,
58
+ Arel::Nodes::Matches,
59
+ Arel::Nodes::NotEqual,
60
+ Arel::Nodes::NotIn,
61
+ Arel::Nodes::Or,
62
+ Arel::Nodes::TableAlias,
63
+ Arel::Nodes::Values,
64
+ Arel::Nodes::As,
65
+ Arel::Nodes::DeleteStatement,
66
+ Arel::Nodes::Ordering,
67
+ Arel::Nodes::JoinSource,
68
+ ].each do |klass|
69
+ define_method("test_#{klass.name.gsub('::', '_')}") do
70
+ binary = klass.new(:a, :b)
71
+ @visitor.accept binary
72
+ end
73
+ end
27
74
  end
28
75
  end
29
76
  end
@@ -0,0 +1,27 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ module Visitors
5
+ describe 'the ibm_db visitor' do
6
+ before do
7
+ @visitor = IBM_DB.new Table.engine
8
+ end
9
+
10
+ it 'uses FETCH FIRST n ROWS to limit results' do
11
+ stmt = Nodes::SelectStatement.new
12
+ stmt.limit = Nodes::Limit.new(1)
13
+ sql = @visitor.accept(stmt)
14
+ sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY"
15
+ end
16
+
17
+ it 'uses FETCH FIRST n ROWS in updates with a limit' do
18
+ stmt = Nodes::UpdateStatement.new
19
+ stmt.limit = Nodes::Limit.new(1)
20
+ stmt.key = 'id'
21
+ sql = @visitor.accept(stmt)
22
+ sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT 'id' FETCH FIRST 1 ROWS ONLY)"
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -4,15 +4,21 @@ module Arel
4
4
  module Visitors
5
5
  describe 'the join_sql visitor' do
6
6
  before do
7
- @visitor = JoinSql.new Table.engine
7
+ @visitor = ToSql.new Table.engine
8
+ @visitor.extend(JoinSql)
9
+ end
10
+
11
+ it 'should visit string join' do
12
+ sql = @visitor.accept Nodes::StringJoin.new('omg')
13
+ sql.must_be_like "'omg'"
8
14
  end
9
15
 
10
16
  describe 'inner join' do
11
17
  it 'should visit left if left is a join' do
12
18
  t = Table.new :users
13
- join = Nodes::InnerJoin.new t, t, Nodes::On.new(t[:id])
14
- j2 = Nodes::InnerJoin.new join, t, Nodes::On.new(t[:id])
15
- @visitor.accept(j2).must_be_like %{
19
+ sm = t.select_manager
20
+ sm.join(t).on(t[:id]).join(t).on(t[:id])
21
+ sm.join_sql.must_be_like %{
16
22
  INNER JOIN "users" ON "users"."id"
17
23
  INNER JOIN "users" ON "users"."id"
18
24
  }
@@ -22,9 +28,10 @@ module Arel
22
28
  describe 'outer join' do
23
29
  it 'should visit left if left is a join' do
24
30
  t = Table.new :users
25
- join = Nodes::OuterJoin.new t, t, Nodes::On.new(t[:id])
26
- j2 = Nodes::OuterJoin.new join, t, Nodes::On.new(t[:id])
27
- @visitor.accept(j2).must_be_like %{
31
+ sm = t.select_manager
32
+ sm.join(t, Nodes::OuterJoin).on(t[:id]).join(
33
+ t, Nodes::OuterJoin).on(t[:id])
34
+ sm.join_sql.must_be_like %{
28
35
  LEFT OUTER JOIN "users" ON "users"."id"
29
36
  LEFT OUTER JOIN "users" ON "users"."id"
30
37
  }
@@ -13,6 +13,15 @@ module Arel
13
13
  sql = @visitor.accept(stmt)
14
14
  sql.must_be_like "SELECT TOP 1"
15
15
  end
16
+
17
+ it 'uses TOP in updates with a limit' do
18
+ stmt = Nodes::UpdateStatement.new
19
+ stmt.limit = Nodes::Limit.new(1)
20
+ stmt.key = 'id'
21
+ sql = @visitor.accept(stmt)
22
+ sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT TOP 1 'id' )"
23
+ end
24
+
16
25
  end
17
26
  end
18
27
  end
@@ -101,7 +101,7 @@ module Arel
101
101
  sql.must_be_like %{
102
102
  SELECT * FROM (
103
103
  SELECT raw_sql_.*, rownum raw_rnum_
104
- FROM (SELECT ) raw_sql_
104
+ FROM (SELECT) raw_sql_
105
105
  WHERE rownum <= 20
106
106
  )
107
107
  WHERE raw_rnum_ > 10
@@ -126,21 +126,22 @@ module Arel
126
126
  sql.must_be_like %{
127
127
  SELECT * FROM (
128
128
  SELECT raw_sql_.*, rownum raw_rnum_
129
- FROM (SELECT ) raw_sql_
129
+ FROM (SELECT) raw_sql_
130
130
  )
131
131
  WHERE raw_rnum_ > 10
132
132
  }
133
133
  end
134
134
  end
135
135
 
136
- it 'modified except to be minus' do
137
- left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10")
138
- right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20")
139
- sql = @visitor.accept Nodes::Except.new(left, right)
140
- sql.must_be_like %{
141
- ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 )
142
- }
143
- end
136
+ end
137
+
138
+ it 'modified except to be minus' do
139
+ left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10")
140
+ right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20")
141
+ sql = @visitor.accept Nodes::Except.new(left, right)
142
+ sql.must_be_like %{
143
+ ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 )
144
+ }
144
145
  end
145
146
  end
146
147
  end
@@ -31,6 +31,18 @@ module Arel
31
31
  assert_match(/LIMIT 'omg'/, sql)
32
32
  assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit'
33
33
  end
34
+
35
+ it 'should support DISTINCT ON' do
36
+ core = Arel::Nodes::SelectCore.new
37
+ core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron'))
38
+ assert_match 'DISTINCT ON ( aaron )', @visitor.accept(core)
39
+ end
40
+
41
+ it 'should support DISTINCT' do
42
+ core = Arel::Nodes::SelectCore.new
43
+ core.set_quantifier = Arel::Nodes::Distinct.new
44
+ assert_equal 'SELECT DISTINCT', @visitor.accept(core)
45
+ end
34
46
  end
35
47
  end
36
48
  end
@@ -5,22 +5,30 @@ module Arel
5
5
  describe 'the to_sql visitor' do
6
6
  before do
7
7
  @visitor = ToSql.new Table.engine
8
- @attr = Table.new(:users)[:id]
8
+ @table = Table.new(:users)
9
+ @attr = @table[:id]
9
10
  end
10
11
 
11
- it "should be thread safe around usage of last_column" do
12
- table = Table.new(:users)
12
+ it 'should not quote sql literals' do
13
+ node = @table[Arel.star]
14
+ sql = @visitor.accept node
15
+ sql.must_be_like '"users".*'
16
+ end
13
17
 
14
- visit_integer_column = Thread.new do
15
- Thread.stop
16
- @visitor.send(:visit_Arel_Attributes_Attribute, @attr)
17
- end
18
+ it 'should visit named functions' do
19
+ function = Nodes::NamedFunction.new('omg', [Arel.star])
20
+ assert_equal 'omg(*)', @visitor.accept(function)
21
+ end
18
22
 
19
- @visitor.accept(table[:name])
20
- assert_equal(:string, @visitor.send(:last_column).type)
21
- visit_integer_column.run
22
- visit_integer_column.join
23
- assert_equal(:string, @visitor.send(:last_column).type)
23
+ it 'should chain predications on named functions' do
24
+ function = Nodes::NamedFunction.new('omg', [Arel.star])
25
+ sql = @visitor.accept(function.eq(2))
26
+ sql.must_be_like %{ omg(*) = 2 }
27
+ end
28
+
29
+ it 'works with lists' do
30
+ function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star])
31
+ assert_equal 'omg(*, *)', @visitor.accept(function)
24
32
  end
25
33
 
26
34
  describe 'equality' do
@@ -65,7 +73,7 @@ module Arel
65
73
  end
66
74
 
67
75
  it "should apply Not to the whole expression" do
68
- node = Nodes::And.new @attr.eq(10), @attr.eq(11)
76
+ node = Nodes::And.new [@attr.eq(10), @attr.eq(11)]
69
77
  sql = @visitor.accept Nodes::Not.new(node)
70
78
  sql.must_be_like %{NOT ("users"."id" = 10 AND "users"."id" = 11)}
71
79
  end
@@ -97,7 +105,7 @@ module Arel
97
105
  end
98
106
 
99
107
  it "should visit_Arel_Nodes_And" do
100
- node = Nodes::And.new @attr.eq(10), @attr.eq(11)
108
+ node = Nodes::And.new [@attr.eq(10), @attr.eq(11)]
101
109
  @visitor.accept(node).must_be_like %{
102
110
  "users"."id" = 10 AND "users"."id" = 11
103
111
  }
@@ -111,7 +119,7 @@ module Arel
111
119
  end
112
120
 
113
121
  it "should visit visit_Arel_Attributes_Time" do
114
- attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column)
122
+ attr = Attributes::Time.new(@attr.relation, @attr.name)
115
123
  @visitor.accept attr
116
124
  end
117
125
 
@@ -179,11 +187,44 @@ module Arel
179
187
  end
180
188
  in_node = Nodes::In.new @attr, %w{ a b c }
181
189
  visitor = visitor.new(Table.engine)
182
- visitor.expected = @attr.column
190
+ visitor.expected = Table.engine.connection.columns(:users).find { |x|
191
+ x.name == 'name'
192
+ }
183
193
  visitor.accept(in_node).must_equal %("users"."name" IN ('a', 'b', 'c'))
184
194
  end
185
195
  end
186
196
 
197
+ describe "Nodes::InfixOperation" do
198
+ it "should handle Multiplication" do
199
+ node = Arel::Attributes::Decimal.new(Table.new(:products), :price) * Arel::Attributes::Decimal.new(Table.new(:currency_rates), :rate)
200
+ @visitor.accept(node).must_equal %("products"."price" * "currency_rates"."rate")
201
+ end
202
+
203
+ it "should handle Division" do
204
+ node = Arel::Attributes::Decimal.new(Table.new(:products), :price) / 5
205
+ @visitor.accept(node).must_equal %("products"."price" / 5)
206
+ end
207
+
208
+ it "should handle Addition" do
209
+ node = Arel::Attributes::Decimal.new(Table.new(:products), :price) + 6
210
+ @visitor.accept(node).must_equal %(("products"."price" + 6))
211
+ end
212
+
213
+ it "should handle Subtraction" do
214
+ node = Arel::Attributes::Decimal.new(Table.new(:products), :price) - 7
215
+ @visitor.accept(node).must_equal %(("products"."price" - 7))
216
+ end
217
+
218
+ it "should handle arbitrary operators" do
219
+ node = Arel::Nodes::InfixOperation.new(
220
+ '||',
221
+ Arel::Attributes::String.new(Table.new(:products), :name),
222
+ Arel::Attributes::String.new(Table.new(:products), :name)
223
+ )
224
+ @visitor.accept(node).must_equal %("products"."name" || "products"."name")
225
+ end
226
+ end
227
+
187
228
  describe "Nodes::NotIn" do
188
229
  it "should know how to visit" do
189
230
  node = @attr.not_in [1, 2, 3]
@@ -234,7 +275,9 @@ module Arel
234
275
  end
235
276
  in_node = Nodes::NotIn.new @attr, %w{ a b c }
236
277
  visitor = visitor.new(Table.engine)
237
- visitor.expected = @attr.column
278
+ visitor.expected = Table.engine.connection.columns(:users).find { |x|
279
+ x.name == 'name'
280
+ }
238
281
  visitor.accept(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c'))
239
282
  end
240
283
  end
@@ -247,6 +290,26 @@ module Arel
247
290
  }
248
291
  end
249
292
  end
293
+
294
+ describe 'TableAlias' do
295
+ it "should use the underlying table for checking columns" do
296
+ test = Table.new(:users).alias('zomgusers')[:id].eq '3'
297
+ @visitor.accept(test).must_be_like %{
298
+ "zomgusers"."id" = 3
299
+ }
300
+ end
301
+ end
302
+
303
+ describe 'distinct on' do
304
+ it 'raises not implemented error' do
305
+ core = Arel::Nodes::SelectCore.new
306
+ core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron'))
307
+
308
+ assert_raises(NotImplementedError) do
309
+ @visitor.accept(core)
310
+ end
311
+ end
312
+ end
250
313
  end
251
314
  end
252
315
  end