arel 6.0.0.beta2 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +1 -1
  3. data/README.markdown +5 -5
  4. data/lib/arel.rb +1 -1
  5. data/lib/arel/collectors/sql_string.rb +7 -1
  6. data/lib/arel/expressions.rb +5 -4
  7. data/lib/arel/nodes.rb +1 -0
  8. data/lib/arel/nodes/bind_param.rb +6 -0
  9. data/lib/arel/nodes/sql_literal.rb +0 -3
  10. data/lib/arel/predications.rb +2 -2
  11. data/lib/arel/visitors/depth_first.rb +6 -0
  12. data/lib/arel/visitors/oracle.rb +4 -0
  13. data/lib/arel/visitors/postgresql.rb +4 -0
  14. data/lib/arel/visitors/reduce.rb +4 -4
  15. data/lib/arel/visitors/to_sql.rb +3 -2
  16. data/lib/arel/visitors/visitor.rb +15 -15
  17. metadata +26 -69
  18. data/.gitignore +0 -9
  19. data/.travis.yml +0 -18
  20. data/Gemfile +0 -5
  21. data/Rakefile +0 -15
  22. data/arel.gemspec +0 -24
  23. data/test/attributes/test_attribute.rb +0 -910
  24. data/test/collectors/test_bind_collector.rb +0 -70
  25. data/test/collectors/test_sql_string.rb +0 -38
  26. data/test/helper.rb +0 -22
  27. data/test/nodes/test_and.rb +0 -20
  28. data/test/nodes/test_as.rb +0 -34
  29. data/test/nodes/test_ascending.rb +0 -44
  30. data/test/nodes/test_bin.rb +0 -33
  31. data/test/nodes/test_binary.rb +0 -26
  32. data/test/nodes/test_count.rb +0 -33
  33. data/test/nodes/test_delete_statement.rb +0 -34
  34. data/test/nodes/test_descending.rb +0 -44
  35. data/test/nodes/test_distinct.rb +0 -20
  36. data/test/nodes/test_equality.rb +0 -84
  37. data/test/nodes/test_extract.rb +0 -41
  38. data/test/nodes/test_false.rb +0 -20
  39. data/test/nodes/test_grouping.rb +0 -25
  40. data/test/nodes/test_infix_operation.rb +0 -40
  41. data/test/nodes/test_insert_statement.rb +0 -42
  42. data/test/nodes/test_named_function.rb +0 -46
  43. data/test/nodes/test_node.rb +0 -39
  44. data/test/nodes/test_not.rb +0 -29
  45. data/test/nodes/test_or.rb +0 -34
  46. data/test/nodes/test_over.rb +0 -67
  47. data/test/nodes/test_select_core.rb +0 -69
  48. data/test/nodes/test_select_statement.rb +0 -49
  49. data/test/nodes/test_sql_literal.rb +0 -73
  50. data/test/nodes/test_sum.rb +0 -24
  51. data/test/nodes/test_table_alias.rb +0 -36
  52. data/test/nodes/test_true.rb +0 -21
  53. data/test/nodes/test_update_statement.rb +0 -58
  54. data/test/nodes/test_window.rb +0 -79
  55. data/test/support/fake_record.rb +0 -135
  56. data/test/test_attributes.rb +0 -66
  57. data/test/test_crud.rb +0 -63
  58. data/test/test_delete_manager.rb +0 -42
  59. data/test/test_factory_methods.rb +0 -44
  60. data/test/test_insert_manager.rb +0 -171
  61. data/test/test_select_manager.rb +0 -1181
  62. data/test/test_table.rb +0 -253
  63. data/test/test_update_manager.rb +0 -124
  64. data/test/visitors/test_bind_visitor.rb +0 -60
  65. data/test/visitors/test_depth_first.rb +0 -258
  66. data/test/visitors/test_dispatch_contamination.rb +0 -22
  67. data/test/visitors/test_dot.rb +0 -76
  68. data/test/visitors/test_ibm_db.rb +0 -33
  69. data/test/visitors/test_informix.rb +0 -58
  70. data/test/visitors/test_mssql.rb +0 -70
  71. data/test/visitors/test_mysql.rb +0 -60
  72. data/test/visitors/test_oracle.rb +0 -170
  73. data/test/visitors/test_postgres.rb +0 -122
  74. data/test/visitors/test_sqlite.rb +0 -23
  75. data/test/visitors/test_to_sql.rb +0 -598
@@ -1,22 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'avoiding contamination between visitor dispatch tables' do
6
- before do
7
- @connection = Table.engine.connection
8
- @table = Table.new(:users)
9
- end
10
-
11
- it 'dispatches properly after failing upwards' do
12
- node = Nodes::Union.new(Nodes::True.new, Nodes::False.new)
13
- assert_equal "( TRUE UNION FALSE )", node.to_sql
14
-
15
- node.first # from Nodes::Node's Enumerable mixin
16
-
17
- assert_equal "( TRUE UNION FALSE )", node.to_sql
18
- end
19
- end
20
- end
21
- end
22
-
@@ -1,76 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- class TestDot < Minitest::Test
6
- def setup
7
- @visitor = Visitors::Dot.new
8
- end
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, Collectors::PlainString.new
21
- end
22
- end
23
-
24
- def test_named_function
25
- func = Nodes::NamedFunction.new 'omg', 'omg'
26
- @visitor.accept func, Collectors::PlainString.new
27
- end
28
-
29
- # unary ops
30
- [
31
- Arel::Nodes::Not,
32
- Arel::Nodes::Group,
33
- Arel::Nodes::On,
34
- Arel::Nodes::Grouping,
35
- Arel::Nodes::Offset,
36
- Arel::Nodes::Ordering,
37
- Arel::Nodes::Having,
38
- Arel::Nodes::UnqualifiedColumn,
39
- Arel::Nodes::Top,
40
- Arel::Nodes::Limit,
41
- ].each do |klass|
42
- define_method("test_#{klass.name.gsub('::', '_')}") do
43
- op = klass.new(:a)
44
- @visitor.accept op, Collectors::PlainString.new
45
- end
46
- end
47
-
48
- # binary ops
49
- [
50
- Arel::Nodes::Assignment,
51
- Arel::Nodes::Between,
52
- Arel::Nodes::DoesNotMatch,
53
- Arel::Nodes::Equality,
54
- Arel::Nodes::GreaterThan,
55
- Arel::Nodes::GreaterThanOrEqual,
56
- Arel::Nodes::In,
57
- Arel::Nodes::LessThan,
58
- Arel::Nodes::LessThanOrEqual,
59
- Arel::Nodes::Matches,
60
- Arel::Nodes::NotEqual,
61
- Arel::Nodes::NotIn,
62
- Arel::Nodes::Or,
63
- Arel::Nodes::TableAlias,
64
- Arel::Nodes::Values,
65
- Arel::Nodes::As,
66
- Arel::Nodes::DeleteStatement,
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, Collectors::PlainString.new
72
- end
73
- end
74
- end
75
- end
76
- end
@@ -1,33 +0,0 @@
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.connection
8
- end
9
-
10
- def compile node
11
- @visitor.accept(node, Collectors::SQLString.new).value
12
- end
13
-
14
- it 'uses FETCH FIRST n ROWS to limit results' do
15
- stmt = Nodes::SelectStatement.new
16
- stmt.limit = Nodes::Limit.new(1)
17
- sql = compile(stmt)
18
- sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY"
19
- end
20
-
21
- it 'uses FETCH FIRST n ROWS in updates with a limit' do
22
- table = Table.new(:users)
23
- stmt = Nodes::UpdateStatement.new
24
- stmt.relation = table
25
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1))
26
- stmt.key = table[:id]
27
- sql = compile(stmt)
28
- sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)"
29
- end
30
-
31
- end
32
- end
33
- end
@@ -1,58 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the informix visitor' do
6
- before do
7
- @visitor = Informix.new Table.engine.connection
8
- end
9
-
10
- def compile node
11
- @visitor.accept(node, Collectors::SQLString.new).value
12
- end
13
-
14
- it 'uses FIRST n to limit results' do
15
- stmt = Nodes::SelectStatement.new
16
- stmt.limit = Nodes::Limit.new(1)
17
- sql = compile(stmt)
18
- sql.must_be_like "SELECT FIRST 1"
19
- end
20
-
21
- it 'uses FIRST n in updates with a limit' do
22
- table = Table.new(:users)
23
- stmt = Nodes::UpdateStatement.new
24
- stmt.relation = table
25
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1))
26
- stmt.key = table[:id]
27
- sql = compile(stmt)
28
- sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT FIRST 1 \"users\".\"id\" FROM \"users\")"
29
- end
30
-
31
- it 'uses SKIP n to jump results' do
32
- stmt = Nodes::SelectStatement.new
33
- stmt.offset = Nodes::Offset.new(10)
34
- sql = compile(stmt)
35
- sql.must_be_like "SELECT SKIP 10"
36
- end
37
-
38
- it 'uses SKIP before FIRST' do
39
- stmt = Nodes::SelectStatement.new
40
- stmt.limit = Nodes::Limit.new(1)
41
- stmt.offset = Nodes::Offset.new(1)
42
- sql = compile(stmt)
43
- sql.must_be_like "SELECT SKIP 1 FIRST 1"
44
- end
45
-
46
- it 'uses INNER JOIN to perform joins' do
47
- core = Nodes::SelectCore.new
48
- table = Table.new(:posts)
49
- core.source = Nodes::JoinSource.new(table, [table.create_join(Table.new(:comments))])
50
-
51
- stmt = Nodes::SelectStatement.new([core])
52
- sql = compile(stmt)
53
- sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"'
54
- end
55
-
56
- end
57
- end
58
- end
@@ -1,70 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the mssql visitor' do
6
- before do
7
- @visitor = MSSQL.new Table.engine.connection
8
- @table = Arel::Table.new "users"
9
- end
10
-
11
- def compile node
12
- @visitor.accept(node, Collectors::SQLString.new).value
13
- end
14
-
15
- it 'should not modify query if no offset or limit' do
16
- stmt = Nodes::SelectStatement.new
17
- sql = compile(stmt)
18
- sql.must_be_like "SELECT"
19
- end
20
-
21
- it 'should go over table PK if no .order() or .group()' do
22
- stmt = Nodes::SelectStatement.new
23
- stmt.cores.first.from = @table
24
- stmt.limit = Nodes::Limit.new(10)
25
- sql = compile(stmt)
26
- sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY \"users\".\"id\") as _row_num FROM \"users\") as _t WHERE _row_num BETWEEN 1 AND 10"
27
- end
28
-
29
- it 'should go over query ORDER BY if .order()' do
30
- stmt = Nodes::SelectStatement.new
31
- stmt.limit = Nodes::Limit.new(10)
32
- stmt.orders << Nodes::SqlLiteral.new('order_by')
33
- sql = compile(stmt)
34
- sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY order_by) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10"
35
- end
36
-
37
- it 'should go over query GROUP BY if no .order() and there is .group()' do
38
- stmt = Nodes::SelectStatement.new
39
- stmt.cores.first.groups << Nodes::SqlLiteral.new('group_by')
40
- stmt.limit = Nodes::Limit.new(10)
41
- sql = compile(stmt)
42
- sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY group_by) as _row_num GROUP BY group_by) as _t WHERE _row_num BETWEEN 1 AND 10"
43
- end
44
-
45
- it 'should use BETWEEN if both .limit() and .offset' do
46
- stmt = Nodes::SelectStatement.new
47
- stmt.limit = Nodes::Limit.new(10)
48
- stmt.offset = Nodes::Offset.new(20)
49
- sql = compile(stmt)
50
- sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 21 AND 30"
51
- end
52
-
53
- it 'should use >= if only .offset' do
54
- stmt = Nodes::SelectStatement.new
55
- stmt.offset = Nodes::Offset.new(20)
56
- sql = compile(stmt)
57
- sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num >= 21"
58
- end
59
-
60
- it 'should generate subquery for .count' do
61
- stmt = Nodes::SelectStatement.new
62
- stmt.limit = Nodes::Limit.new(10)
63
- stmt.cores.first.projections << Nodes::Count.new('*')
64
- sql = compile(stmt)
65
- sql.must_be_like "SELECT COUNT(1) as count_id FROM (SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10) AS subquery"
66
- end
67
-
68
- end
69
- end
70
- end
@@ -1,60 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the mysql visitor' do
6
- before do
7
- @visitor = MySQL.new Table.engine.connection
8
- end
9
-
10
- def compile node
11
- @visitor.accept(node, Collectors::SQLString.new).value
12
- end
13
-
14
- it 'squashes parenthesis on multiple unions' do
15
- subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right')
16
- node = Nodes::Union.new subnode, Arel.sql('topright')
17
- assert_equal 1, compile(node).scan('(').length
18
-
19
- subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right')
20
- node = Nodes::Union.new Arel.sql('topleft'), subnode
21
- assert_equal 1, compile(node).scan('(').length
22
- end
23
-
24
- ###
25
- # :'(
26
- # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
27
- it 'defaults limit to 18446744073709551615' do
28
- stmt = Nodes::SelectStatement.new
29
- stmt.offset = Nodes::Offset.new(1)
30
- sql = compile(stmt)
31
- sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1"
32
- end
33
-
34
- it "should escape LIMIT" do
35
- sc = Arel::Nodes::UpdateStatement.new
36
- sc.relation = Table.new(:users)
37
- sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg"))
38
- assert_equal("UPDATE \"users\" LIMIT 'omg'", compile(sc))
39
- end
40
-
41
- it 'uses DUAL for empty from' do
42
- stmt = Nodes::SelectStatement.new
43
- sql = compile(stmt)
44
- sql.must_be_like "SELECT FROM DUAL"
45
- end
46
-
47
- describe 'locking' do
48
- it 'defaults to FOR UPDATE when locking' do
49
- node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
50
- compile(node).must_be_like "FOR UPDATE"
51
- end
52
-
53
- it 'allows a custom string to be used as a lock' do
54
- node = Nodes::Lock.new(Arel.sql('LOCK IN SHARE MODE'))
55
- compile(node).must_be_like "LOCK IN SHARE MODE"
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,170 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the oracle visitor' do
6
- before do
7
- @visitor = Oracle.new Table.engine.connection_pool
8
- end
9
-
10
- def compile node
11
- @visitor.accept(node, Collectors::SQLString.new).value
12
- end
13
-
14
- it 'modifies order when there is distinct and first value' do
15
- # *sigh*
16
- select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
17
- stmt = Nodes::SelectStatement.new
18
- stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
19
- stmt.orders << Nodes::SqlLiteral.new('foo')
20
- sql = compile(stmt)
21
- sql.must_be_like %{
22
- SELECT #{select} ORDER BY alias_0__
23
- }
24
- end
25
-
26
- it 'is idempotent with crazy query' do
27
- # *sigh*
28
- select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
29
- stmt = Nodes::SelectStatement.new
30
- stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
31
- stmt.orders << Nodes::SqlLiteral.new('foo')
32
-
33
- sql = compile(stmt)
34
- sql2 = compile(stmt)
35
- sql.must_equal sql2
36
- end
37
-
38
- it 'splits orders with commas' do
39
- # *sigh*
40
- select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
41
- stmt = Nodes::SelectStatement.new
42
- stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
43
- stmt.orders << Nodes::SqlLiteral.new('foo, bar')
44
- sql = compile(stmt)
45
- sql.must_be_like %{
46
- SELECT #{select} ORDER BY alias_0__, alias_1__
47
- }
48
- end
49
-
50
- it 'splits orders with commas and function calls' do
51
- # *sigh*
52
- select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__"
53
- stmt = Nodes::SelectStatement.new
54
- stmt.cores.first.projections << Nodes::SqlLiteral.new(select)
55
- stmt.orders << Nodes::SqlLiteral.new('NVL(LOWER(bar, foo), foo) DESC, UPPER(baz)')
56
- sql = compile(stmt)
57
- sql.must_be_like %{
58
- SELECT #{select} ORDER BY alias_0__ DESC, alias_1__
59
- }
60
- end
61
-
62
- describe 'Nodes::SelectStatement' do
63
- describe 'limit' do
64
- it 'adds a rownum clause' do
65
- stmt = Nodes::SelectStatement.new
66
- stmt.limit = Nodes::Limit.new(10)
67
- sql = compile stmt
68
- sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 }
69
- end
70
-
71
- it 'is idempotent' do
72
- stmt = Nodes::SelectStatement.new
73
- stmt.orders << Nodes::SqlLiteral.new('foo')
74
- stmt.limit = Nodes::Limit.new(10)
75
- sql = compile stmt
76
- sql2 = compile stmt
77
- sql.must_equal sql2
78
- end
79
-
80
- it 'creates a subquery when there is order_by' do
81
- stmt = Nodes::SelectStatement.new
82
- stmt.orders << Nodes::SqlLiteral.new('foo')
83
- stmt.limit = Nodes::Limit.new(10)
84
- sql = compile stmt
85
- sql.must_be_like %{
86
- SELECT * FROM (SELECT ORDER BY foo ) WHERE ROWNUM <= 10
87
- }
88
- end
89
-
90
- it 'creates a subquery when there is group by' do
91
- stmt = Nodes::SelectStatement.new
92
- stmt.cores.first.groups << Nodes::SqlLiteral.new('foo')
93
- stmt.limit = Nodes::Limit.new(10)
94
- sql = compile stmt
95
- sql.must_be_like %{
96
- SELECT * FROM (SELECT GROUP BY foo ) WHERE ROWNUM <= 10
97
- }
98
- end
99
-
100
- it 'creates a subquery when there is DISTINCT' do
101
- stmt = Nodes::SelectStatement.new
102
- stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new
103
- stmt.cores.first.projections << Nodes::SqlLiteral.new('id')
104
- stmt.limit = Arel::Nodes::Limit.new(10)
105
- sql = compile stmt
106
- sql.must_be_like %{
107
- SELECT * FROM (SELECT DISTINCT id ) WHERE ROWNUM <= 10
108
- }
109
- end
110
-
111
- it 'creates a different subquery when there is an offset' do
112
- stmt = Nodes::SelectStatement.new
113
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10))
114
- stmt.offset = Nodes::Offset.new(10)
115
- sql = compile stmt
116
- sql.must_be_like %{
117
- SELECT * FROM (
118
- SELECT raw_sql_.*, rownum raw_rnum_
119
- FROM (SELECT ) raw_sql_
120
- WHERE rownum <= 20
121
- )
122
- WHERE raw_rnum_ > 10
123
- }
124
- end
125
-
126
- it 'is idempotent with different subquery' do
127
- stmt = Nodes::SelectStatement.new
128
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10))
129
- stmt.offset = Nodes::Offset.new(10)
130
- sql = compile stmt
131
- sql2 = compile stmt
132
- sql.must_equal sql2
133
- end
134
- end
135
-
136
- describe 'only offset' do
137
- it 'creates a select from subquery with rownum condition' do
138
- stmt = Nodes::SelectStatement.new
139
- stmt.offset = Nodes::Offset.new(10)
140
- sql = compile stmt
141
- sql.must_be_like %{
142
- SELECT * FROM (
143
- SELECT raw_sql_.*, rownum raw_rnum_
144
- FROM (SELECT) raw_sql_
145
- )
146
- WHERE raw_rnum_ > 10
147
- }
148
- end
149
- end
150
-
151
- end
152
-
153
- it 'modified except to be minus' do
154
- left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10")
155
- right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20")
156
- sql = compile Nodes::Except.new(left, right)
157
- sql.must_be_like %{
158
- ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 )
159
- }
160
- end
161
-
162
- describe 'locking' do
163
- it 'defaults to FOR UPDATE when locking' do
164
- node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
165
- compile(node).must_be_like "FOR UPDATE"
166
- end
167
- end
168
- end
169
- end
170
- end