arel 6.0.0.beta2 → 6.0.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 (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