arel 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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