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.
- data/History.txt +51 -4
- data/Manifest.txt +15 -31
- data/README.markdown +27 -3
- data/Rakefile +0 -2
- data/arel.gemspec +20 -19
- data/lib/arel.rb +9 -1
- data/lib/arel/alias_predication.rb +7 -0
- data/lib/arel/attributes/attribute.rb +10 -1
- data/lib/arel/crud.rb +43 -8
- data/lib/arel/expression.rb +1 -0
- data/lib/arel/factory_methods.rb +35 -0
- data/lib/arel/insert_manager.rb +5 -1
- data/lib/arel/math.rb +19 -0
- data/lib/arel/nodes.rb +32 -42
- data/lib/arel/nodes/and.rb +18 -1
- data/lib/arel/nodes/binary.rb +28 -0
- data/lib/arel/nodes/count.rb +0 -3
- data/lib/arel/nodes/function.rb +13 -2
- data/lib/arel/nodes/infix_operation.rb +43 -0
- data/lib/arel/nodes/join_source.rb +14 -0
- data/lib/arel/nodes/named_function.rb +14 -0
- data/lib/arel/nodes/node.rb +5 -2
- data/lib/arel/nodes/select_core.rb +24 -10
- data/lib/arel/nodes/select_statement.rb +8 -6
- data/lib/arel/nodes/sql_literal.rb +2 -0
- data/lib/arel/nodes/string_join.rb +2 -4
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/{as.rb → terminal.rb} +1 -1
- data/lib/arel/nodes/unary.rb +17 -0
- data/lib/arel/nodes/unqualified_column.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes/with.rb +10 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +6 -24
- data/lib/arel/select_manager.rb +95 -40
- data/lib/arel/table.rb +32 -19
- data/lib/arel/tree_manager.rb +1 -0
- data/lib/arel/update_manager.rb +4 -0
- data/lib/arel/visitors.rb +2 -0
- data/lib/arel/visitors/depth_first.rb +19 -9
- data/lib/arel/visitors/dot.rb +42 -25
- data/lib/arel/visitors/ibm_db.rb +12 -0
- data/lib/arel/visitors/join_sql.rb +2 -23
- data/lib/arel/visitors/mssql.rb +7 -0
- data/lib/arel/visitors/mysql.rb +4 -0
- data/lib/arel/visitors/oracle.rb +2 -2
- data/lib/arel/visitors/postgresql.rb +2 -38
- data/lib/arel/visitors/to_sql.rb +148 -67
- data/test/attributes/test_attribute.rb +3 -3
- data/test/helper.rb +1 -1
- data/test/nodes/test_as.rb +6 -0
- data/test/nodes/test_bin.rb +23 -0
- data/test/nodes/test_named_function.rb +30 -0
- data/test/nodes/test_node.rb +10 -0
- data/test/nodes/test_not.rb +4 -7
- data/test/nodes/test_select_core.rb +23 -14
- data/test/support/fake_record.rb +21 -4
- data/test/test_attributes.rb +8 -0
- data/test/test_crud.rb +6 -12
- data/test/test_factory_methods.rb +34 -0
- data/test/test_insert_manager.rb +19 -0
- data/test/test_select_manager.rb +343 -64
- data/test/test_table.rb +36 -45
- data/test/visitors/test_depth_first.rb +29 -11
- data/test/visitors/test_dot.rb +47 -0
- data/test/visitors/test_ibm_db.rb +27 -0
- data/test/visitors/test_join_sql.rb +14 -7
- data/test/visitors/test_mssql.rb +9 -0
- data/test/visitors/test_oracle.rb +11 -10
- data/test/visitors/test_postgres.rb +12 -0
- data/test/visitors/test_to_sql.rb +80 -17
- metadata +80 -101
- data/lib/arel/nodes/assignment.rb +0 -6
- data/lib/arel/nodes/avg.rb +0 -6
- data/lib/arel/nodes/between.rb +0 -6
- data/lib/arel/nodes/does_not_match.rb +0 -6
- data/lib/arel/nodes/except.rb +0 -7
- data/lib/arel/nodes/exists.rb +0 -7
- data/lib/arel/nodes/greater_than.rb +0 -6
- data/lib/arel/nodes/greater_than_or_equal.rb +0 -6
- data/lib/arel/nodes/group.rb +0 -6
- data/lib/arel/nodes/grouping.rb +0 -6
- data/lib/arel/nodes/having.rb +0 -6
- data/lib/arel/nodes/intersect.rb +0 -7
- data/lib/arel/nodes/join.rb +0 -13
- data/lib/arel/nodes/less_than.rb +0 -6
- data/lib/arel/nodes/less_than_or_equal.rb +0 -6
- data/lib/arel/nodes/limit.rb +0 -7
- data/lib/arel/nodes/lock.rb +0 -6
- data/lib/arel/nodes/matches.rb +0 -6
- data/lib/arel/nodes/max.rb +0 -6
- data/lib/arel/nodes/min.rb +0 -6
- data/lib/arel/nodes/not.rb +0 -6
- data/lib/arel/nodes/not_equal.rb +0 -6
- data/lib/arel/nodes/not_in.rb +0 -6
- data/lib/arel/nodes/offset.rb +0 -7
- data/lib/arel/nodes/on.rb +0 -6
- data/lib/arel/nodes/or.rb +0 -6
- data/lib/arel/nodes/sum.rb +0 -6
- data/lib/arel/nodes/top.rb +0 -6
- data/lib/arel/nodes/union.rb +0 -7
- data/lib/arel/nodes/union_all.rb +0 -7
data/test/test_table.rb
CHANGED
@@ -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,
|
53
|
+
func = klass.new(:a, "b")
|
53
54
|
@visitor.accept func
|
54
|
-
assert_equal [:a,
|
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,
|
72
|
+
count = Nodes::Count.new :a, :b, "c"
|
66
73
|
@visitor.accept count
|
67
|
-
assert_equal [:a,
|
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
|
78
|
+
join = Nodes::InnerJoin.new :a, :b
|
72
79
|
@visitor.accept join
|
73
|
-
assert_equal [:a, :b,
|
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
|
84
|
+
join = Nodes::OuterJoin.new :a, :b
|
78
85
|
@visitor.accept join
|
79
|
-
assert_equal [:a, :b,
|
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,
|
data/test/visitors/test_dot.rb
CHANGED
@@ -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 =
|
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
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
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
|
}
|
data/test/visitors/test_mssql.rb
CHANGED
@@ -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
|
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
|
129
|
+
FROM (SELECT) raw_sql_
|
130
130
|
)
|
131
131
|
WHERE raw_rnum_ > 10
|
132
132
|
}
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
@
|
8
|
+
@table = Table.new(:users)
|
9
|
+
@attr = @table[:id]
|
9
10
|
end
|
10
11
|
|
11
|
-
it
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
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 =
|
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 =
|
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
|