arel 2.0.10 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|