square-arel 2.0.9.20110222133018

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/.autotest +26 -0
  2. data/History.txt +105 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/Manifest.txt +124 -0
  5. data/README.markdown +94 -0
  6. data/Rakefile +20 -0
  7. data/lib/arel.rb +39 -0
  8. data/lib/arel/attributes.rb +20 -0
  9. data/lib/arel/attributes/attribute.rb +18 -0
  10. data/lib/arel/compatibility/wheres.rb +33 -0
  11. data/lib/arel/crud.rb +37 -0
  12. data/lib/arel/delete_manager.rb +18 -0
  13. data/lib/arel/deprecated.rb +4 -0
  14. data/lib/arel/expression.rb +4 -0
  15. data/lib/arel/expressions.rb +23 -0
  16. data/lib/arel/insert_manager.rb +34 -0
  17. data/lib/arel/nodes.rb +53 -0
  18. data/lib/arel/nodes/and.rb +6 -0
  19. data/lib/arel/nodes/as.rb +6 -0
  20. data/lib/arel/nodes/assignment.rb +6 -0
  21. data/lib/arel/nodes/avg.rb +6 -0
  22. data/lib/arel/nodes/between.rb +6 -0
  23. data/lib/arel/nodes/binary.rb +12 -0
  24. data/lib/arel/nodes/count.rb +13 -0
  25. data/lib/arel/nodes/delete_statement.rb +19 -0
  26. data/lib/arel/nodes/does_not_match.rb +6 -0
  27. data/lib/arel/nodes/equality.rb +9 -0
  28. data/lib/arel/nodes/except.rb +7 -0
  29. data/lib/arel/nodes/exists.rb +7 -0
  30. data/lib/arel/nodes/function.rb +18 -0
  31. data/lib/arel/nodes/greater_than.rb +6 -0
  32. data/lib/arel/nodes/greater_than_or_equal.rb +6 -0
  33. data/lib/arel/nodes/group.rb +6 -0
  34. data/lib/arel/nodes/grouping.rb +6 -0
  35. data/lib/arel/nodes/having.rb +6 -0
  36. data/lib/arel/nodes/in.rb +6 -0
  37. data/lib/arel/nodes/inner_join.rb +6 -0
  38. data/lib/arel/nodes/insert_statement.rb +19 -0
  39. data/lib/arel/nodes/intersect.rb +7 -0
  40. data/lib/arel/nodes/join.rb +13 -0
  41. data/lib/arel/nodes/less_than.rb +6 -0
  42. data/lib/arel/nodes/less_than_or_equal.rb +6 -0
  43. data/lib/arel/nodes/limit.rb +7 -0
  44. data/lib/arel/nodes/lock.rb +6 -0
  45. data/lib/arel/nodes/matches.rb +6 -0
  46. data/lib/arel/nodes/max.rb +6 -0
  47. data/lib/arel/nodes/min.rb +6 -0
  48. data/lib/arel/nodes/node.rb +44 -0
  49. data/lib/arel/nodes/not.rb +6 -0
  50. data/lib/arel/nodes/not_equal.rb +6 -0
  51. data/lib/arel/nodes/not_in.rb +6 -0
  52. data/lib/arel/nodes/offset.rb +7 -0
  53. data/lib/arel/nodes/on.rb +6 -0
  54. data/lib/arel/nodes/or.rb +6 -0
  55. data/lib/arel/nodes/ordering.rb +20 -0
  56. data/lib/arel/nodes/outer_join.rb +6 -0
  57. data/lib/arel/nodes/select_core.rb +26 -0
  58. data/lib/arel/nodes/select_statement.rb +22 -0
  59. data/lib/arel/nodes/sql_literal.rb +8 -0
  60. data/lib/arel/nodes/string_join.rb +11 -0
  61. data/lib/arel/nodes/sum.rb +6 -0
  62. data/lib/arel/nodes/table_alias.rb +13 -0
  63. data/lib/arel/nodes/top.rb +6 -0
  64. data/lib/arel/nodes/unary.rb +11 -0
  65. data/lib/arel/nodes/union.rb +7 -0
  66. data/lib/arel/nodes/union_all.rb +7 -0
  67. data/lib/arel/nodes/unqualified_column.rb +16 -0
  68. data/lib/arel/nodes/update_statement.rb +21 -0
  69. data/lib/arel/nodes/values.rb +14 -0
  70. data/lib/arel/predications.rb +183 -0
  71. data/lib/arel/relation.rb +6 -0
  72. data/lib/arel/select_manager.rb +237 -0
  73. data/lib/arel/sql/engine.rb +10 -0
  74. data/lib/arel/sql_literal.rb +4 -0
  75. data/lib/arel/table.rb +134 -0
  76. data/lib/arel/tree_manager.rb +36 -0
  77. data/lib/arel/update_manager.rb +49 -0
  78. data/lib/arel/visitors.rb +38 -0
  79. data/lib/arel/visitors/depth_first.rb +154 -0
  80. data/lib/arel/visitors/dot.rb +230 -0
  81. data/lib/arel/visitors/join_sql.rb +40 -0
  82. data/lib/arel/visitors/mssql.rb +16 -0
  83. data/lib/arel/visitors/mysql.rb +34 -0
  84. data/lib/arel/visitors/oracle.rb +116 -0
  85. data/lib/arel/visitors/order_clauses.rb +11 -0
  86. data/lib/arel/visitors/postgresql.rb +58 -0
  87. data/lib/arel/visitors/sqlite.rb +11 -0
  88. data/lib/arel/visitors/to_sql.rb +331 -0
  89. data/lib/arel/visitors/visitor.rb +27 -0
  90. data/lib/arel/visitors/where_sql.rb +9 -0
  91. data/square-arel.gemspec +36 -0
  92. data/test/attributes/test_attribute.rb +664 -0
  93. data/test/helper.rb +13 -0
  94. data/test/nodes/test_as.rb +16 -0
  95. data/test/nodes/test_count.rb +18 -0
  96. data/test/nodes/test_delete_statement.rb +14 -0
  97. data/test/nodes/test_equality.rb +74 -0
  98. data/test/nodes/test_insert_statement.rb +18 -0
  99. data/test/nodes/test_node.rb +33 -0
  100. data/test/nodes/test_not.rb +20 -0
  101. data/test/nodes/test_or.rb +22 -0
  102. data/test/nodes/test_select_core.rb +22 -0
  103. data/test/nodes/test_select_statement.rb +13 -0
  104. data/test/nodes/test_sql_literal.rb +52 -0
  105. data/test/nodes/test_sum.rb +12 -0
  106. data/test/nodes/test_update_statement.rb +18 -0
  107. data/test/support/fake_record.rb +91 -0
  108. data/test/test_activerecord_compat.rb +18 -0
  109. data/test/test_attributes.rb +46 -0
  110. data/test/test_crud.rb +69 -0
  111. data/test/test_delete_manager.rb +42 -0
  112. data/test/test_insert_manager.rb +125 -0
  113. data/test/test_select_manager.rb +659 -0
  114. data/test/test_table.rb +193 -0
  115. data/test/test_update_manager.rb +86 -0
  116. data/test/visitors/test_depth_first.rb +212 -0
  117. data/test/visitors/test_dot.rb +29 -0
  118. data/test/visitors/test_join_sql.rb +35 -0
  119. data/test/visitors/test_mssql.rb +18 -0
  120. data/test/visitors/test_mysql.rb +45 -0
  121. data/test/visitors/test_oracle.rb +147 -0
  122. data/test/visitors/test_postgres.rb +36 -0
  123. data/test/visitors/test_sqlite.rb +18 -0
  124. data/test/visitors/test_to_sql.rb +255 -0
  125. metadata +261 -0
@@ -0,0 +1,18 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'activerecord compatibility' do
5
+ describe 'select manager' do
6
+ it 'provides wheres' do
7
+ table = Table.new :users
8
+ manager = Arel::SelectManager.new Table.engine
9
+ manager.where table[:id].eq 1
10
+ manager.where table[:name].eq 'Aaron'
11
+
12
+ manager.wheres.map { |x|
13
+ x.value
14
+ }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'Attributes' do
5
+ describe 'for' do
6
+ it 'deals with unknown column types' do
7
+ column = Struct.new(:type).new :crazy
8
+ Attributes.for(column).must_equal Attributes::Undefined
9
+ end
10
+
11
+ it 'returns the correct constant for strings' do
12
+ [:string, :text, :binary].each do |type|
13
+ column = Struct.new(:type).new type
14
+ Attributes.for(column).must_equal Attributes::String
15
+ end
16
+ end
17
+
18
+ it 'returns the correct constant for ints' do
19
+ column = Struct.new(:type).new :integer
20
+ Attributes.for(column).must_equal Attributes::Integer
21
+ end
22
+
23
+ it 'returns the correct constant for floats' do
24
+ column = Struct.new(:type).new :float
25
+ Attributes.for(column).must_equal Attributes::Float
26
+ end
27
+
28
+ it 'returns the correct constant for decimals' do
29
+ column = Struct.new(:type).new :decimal
30
+ Attributes.for(column).must_equal Attributes::Decimal
31
+ end
32
+
33
+ it 'returns the correct constant for boolean' do
34
+ column = Struct.new(:type).new :boolean
35
+ Attributes.for(column).must_equal Attributes::Boolean
36
+ end
37
+
38
+ it 'returns the correct constant for time' do
39
+ [:date, :datetime, :timestamp, :time].each do |type|
40
+ column = Struct.new(:type).new type
41
+ Attributes.for(column).must_equal Attributes::Time
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,69 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ class FakeCrudder < SelectManager
5
+ class FakeEngine
6
+ attr_reader :calls, :connection_pool, :spec, :config
7
+
8
+ def initialize
9
+ @calls = []
10
+ @connection_pool = self
11
+ @spec = self
12
+ @config = { :adapter => 'sqlite3' }
13
+ end
14
+
15
+ def connection; self end
16
+
17
+ def method_missing name, *args
18
+ @calls << [name, args]
19
+ end
20
+ end
21
+
22
+ include Crud
23
+
24
+ attr_reader :engine
25
+ attr_accessor :ctx
26
+
27
+ def initialize engine = FakeEngine.new
28
+ super
29
+ end
30
+ end
31
+
32
+ describe 'crud' do
33
+ describe 'insert' do
34
+ it 'should call insert on the connection' do
35
+ table = Table.new :users
36
+ fc = FakeCrudder.new
37
+ fc.from table
38
+ fc.insert [[table[:id], 'foo']]
39
+ fc.engine.calls.find { |method, _|
40
+ method == :insert
41
+ }.wont_be_nil
42
+ end
43
+ end
44
+
45
+ describe 'update' do
46
+ it 'should call update on the connection' do
47
+ table = Table.new :users
48
+ fc = FakeCrudder.new
49
+ fc.from table
50
+ fc.update [[table[:id], 'foo']]
51
+ fc.engine.calls.find { |method, _|
52
+ method == :update
53
+ }.wont_be_nil
54
+ end
55
+ end
56
+
57
+ describe 'delete' do
58
+ it 'should call delete on the connection' do
59
+ table = Table.new :users
60
+ fc = FakeCrudder.new
61
+ fc.from table
62
+ fc.delete
63
+ fc.engine.calls.find { |method, _|
64
+ method == :delete
65
+ }.wont_be_nil
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'delete manager' do
5
+ describe 'new' do
6
+ it 'takes an engine' do
7
+ Arel::DeleteManager.new Table.engine
8
+ end
9
+ end
10
+
11
+ describe 'from' do
12
+ it 'uses from' do
13
+ table = Table.new(:users)
14
+ dm = Arel::DeleteManager.new Table.engine
15
+ dm.from table
16
+ dm.to_sql.must_be_like %{ DELETE FROM "users" }
17
+ end
18
+
19
+ it 'chains' do
20
+ table = Table.new(:users)
21
+ dm = Arel::DeleteManager.new Table.engine
22
+ dm.from(table).must_equal dm
23
+ end
24
+ end
25
+
26
+ describe 'where' do
27
+ it 'uses where values' do
28
+ table = Table.new(:users)
29
+ dm = Arel::DeleteManager.new Table.engine
30
+ dm.from table
31
+ dm.where table[:id].eq(10)
32
+ dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10}
33
+ end
34
+
35
+ it 'chains' do
36
+ table = Table.new(:users)
37
+ dm = Arel::DeleteManager.new Table.engine
38
+ dm.where(table[:id].eq(10)).must_equal dm
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,125 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'insert manager' do
5
+ describe 'new' do
6
+ it 'takes an engine' do
7
+ Arel::InsertManager.new Table.engine
8
+ end
9
+ end
10
+
11
+ describe 'insert' do
12
+ it "inserts false" do
13
+ table = Table.new(:users)
14
+ manager = Arel::InsertManager.new Table.engine
15
+
16
+ manager.insert [[table[:bool], false]]
17
+ manager.to_sql.must_be_like %{
18
+ INSERT INTO "users" ("bool") VALUES ('f')
19
+ }
20
+ end
21
+
22
+ it "inserts null" do
23
+ table = Table.new(:users)
24
+ manager = Arel::InsertManager.new Table.engine
25
+ manager.insert [[table[:id], nil]]
26
+ manager.to_sql.must_be_like %{
27
+ INSERT INTO "users" ("id") VALUES (NULL)
28
+ }
29
+ end
30
+
31
+ it "inserts time" do
32
+ table = Table.new(:users)
33
+ manager = Arel::InsertManager.new Table.engine
34
+
35
+ time = Time.now
36
+ attribute = table[:created_at]
37
+
38
+ manager.insert [[attribute, time]]
39
+ manager.to_sql.must_be_like %{
40
+ INSERT INTO "users" ("created_at") VALUES (#{Table.engine.connection.quote time})
41
+ }
42
+ end
43
+
44
+ it 'takes a list of lists' do
45
+ table = Table.new(:users)
46
+ manager = Arel::InsertManager.new Table.engine
47
+ manager.into table
48
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
49
+ manager.to_sql.must_be_like %{
50
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
51
+ }
52
+ end
53
+
54
+ it 'defaults the table' do
55
+ table = Table.new(:users)
56
+ manager = Arel::InsertManager.new Table.engine
57
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
58
+ manager.to_sql.must_be_like %{
59
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
60
+ }
61
+ end
62
+
63
+ it 'takes an empty list' do
64
+ manager = Arel::InsertManager.new Table.engine
65
+ manager.insert []
66
+ end
67
+ end
68
+
69
+ describe 'into' do
70
+ it 'takes an engine' do
71
+ manager = Arel::InsertManager.new Table.engine
72
+ manager.into(Table.new(:users)).must_equal manager
73
+ end
74
+
75
+ it 'converts to sql' do
76
+ table = Table.new :users
77
+ manager = Arel::InsertManager.new Table.engine
78
+ manager.into table
79
+ manager.to_sql.must_be_like %{
80
+ INSERT INTO "users"
81
+ }
82
+ end
83
+ end
84
+
85
+ describe 'columns' do
86
+ it "converts to sql" do
87
+ table = Table.new :users
88
+ manager = Arel::InsertManager.new Table.engine
89
+ manager.into table
90
+ manager.columns << table[:id]
91
+ manager.to_sql.must_be_like %{
92
+ INSERT INTO "users" ("id")
93
+ }
94
+ end
95
+ end
96
+
97
+ describe "values" do
98
+ it "converts to sql" do
99
+ table = Table.new :users
100
+ manager = Arel::InsertManager.new Table.engine
101
+ manager.into table
102
+
103
+ manager.values = Nodes::Values.new [1]
104
+ manager.to_sql.must_be_like %{
105
+ INSERT INTO "users" VALUES (1)
106
+ }
107
+ end
108
+ end
109
+
110
+ describe "combo" do
111
+ it "puts shit together" do
112
+ table = Table.new :users
113
+ manager = Arel::InsertManager.new Table.engine
114
+ manager.into table
115
+
116
+ manager.values = Nodes::Values.new [1, 'aaron']
117
+ manager.columns << table[:id]
118
+ manager.columns << table[:name]
119
+ manager.to_sql.must_be_like %{
120
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
121
+ }
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,659 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ class EngineProxy
5
+ attr_reader :executed
6
+ attr_reader :connection_pool
7
+ attr_reader :spec
8
+ attr_reader :config
9
+
10
+ def initialize engine
11
+ @engine = engine
12
+ @executed = []
13
+ @connection_pool = self
14
+ @spec = self
15
+ @config = { :adapter => 'sqlite3' }
16
+ end
17
+
18
+ def with_connection
19
+ yield self
20
+ end
21
+
22
+ def connection
23
+ self
24
+ end
25
+
26
+ def quote_table_name thing; @engine.connection.quote_table_name thing end
27
+ def quote_column_name thing; @engine.connection.quote_column_name thing end
28
+ def quote thing, column; @engine.connection.quote thing, column end
29
+
30
+ def execute sql, name = nil, *args
31
+ @executed << sql
32
+ end
33
+ alias :update :execute
34
+ alias :delete :execute
35
+ alias :insert :execute
36
+ end
37
+
38
+ describe 'select manager' do
39
+ describe 'backwards compatibility' do
40
+ describe 'project' do
41
+ it 'accepts symbols as sql literals' do
42
+ table = Table.new :users
43
+ manager = Arel::SelectManager.new Table.engine
44
+ manager.project :id
45
+ manager.from table
46
+ manager.to_sql.must_be_like %{
47
+ SELECT id FROM "users"
48
+ }
49
+ end
50
+ end
51
+
52
+ describe 'order' do
53
+ it 'accepts symbols' do
54
+ table = Table.new :users
55
+ manager = Arel::SelectManager.new Table.engine
56
+ manager.project SqlLiteral.new '*'
57
+ manager.from table
58
+ manager.order :foo
59
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo }
60
+ end
61
+ end
62
+
63
+ describe 'group' do
64
+ it 'takes a symbol' do
65
+ table = Table.new :users
66
+ manager = Arel::SelectManager.new Table.engine
67
+ manager.from table
68
+ manager.group :foo
69
+ manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
70
+ end
71
+ end
72
+
73
+ describe 'from' do
74
+ it 'ignores strings when table of same name exists' do
75
+ table = Table.new :users
76
+ manager = Arel::SelectManager.new Table.engine
77
+
78
+ manager.from table
79
+ manager.from 'users'
80
+ manager.project table['id']
81
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM users'
82
+ end
83
+ end
84
+
85
+ describe '#having' do
86
+ it 'converts strings to SQLLiterals' do
87
+ table = Table.new :users
88
+ mgr = table.from table
89
+ mgr.having 'foo'
90
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo }
91
+ end
92
+ end
93
+
94
+ describe 'on' do
95
+ it 'converts to sqlliterals' do
96
+ table = Table.new :users
97
+ right = table.alias
98
+ mgr = table.from table
99
+ mgr.join(right).on("omg")
100
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg }
101
+ end
102
+
103
+ it 'converts to sqlliterals' do
104
+ table = Table.new :users
105
+ right = table.alias
106
+ mgr = table.from table
107
+ mgr.join(right).on("omg", "123")
108
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg AND 123 }
109
+ end
110
+ end
111
+ end
112
+
113
+ describe 'clone' do
114
+ it 'creates new cores' do
115
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
116
+ mgr = table.from table
117
+ m2 = mgr.clone
118
+ m2.project "foo"
119
+ mgr.to_sql.wont_equal m2.to_sql
120
+ end
121
+ end
122
+
123
+ describe 'initialize' do
124
+ it 'uses alias in sql' do
125
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
126
+ mgr = table.from table
127
+ mgr.skip 10
128
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 }
129
+ end
130
+ end
131
+
132
+ describe 'skip' do
133
+ it 'should add an offset' do
134
+ table = Table.new :users
135
+ mgr = table.from table
136
+ mgr.skip 10
137
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
138
+ end
139
+
140
+ it 'should chain' do
141
+ table = Table.new :users
142
+ mgr = table.from table
143
+ mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
144
+ end
145
+ end
146
+
147
+ describe 'exists' do
148
+ it 'should create an exists clause' do
149
+ table = Table.new(:users)
150
+ manager = Arel::SelectManager.new Table.engine, table
151
+ manager.project SqlLiteral.new '*'
152
+ m2 = Arel::SelectManager.new(manager.engine)
153
+ m2.project manager.exists
154
+ m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) }
155
+ end
156
+
157
+ it 'can be aliased' do
158
+ table = Table.new(:users)
159
+ manager = Arel::SelectManager.new Table.engine, table
160
+ manager.project SqlLiteral.new '*'
161
+ m2 = Arel::SelectManager.new(manager.engine)
162
+ m2.project manager.exists.as('foo')
163
+ m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo }
164
+ end
165
+ end
166
+
167
+ describe 'ast' do
168
+ it 'should return the ast' do
169
+ table = Table.new :users
170
+ mgr = table.from table
171
+ ast = mgr.ast
172
+ mgr.visitor.accept(ast).must_equal mgr.to_sql
173
+ end
174
+ end
175
+
176
+ describe 'taken' do
177
+ it 'should return limit' do
178
+ manager = Arel::SelectManager.new Table.engine
179
+ manager.take 10
180
+ manager.taken.must_equal 10
181
+ end
182
+ end
183
+
184
+ describe 'insert' do
185
+ it 'uses the select FROM' do
186
+ engine = EngineProxy.new Table.engine
187
+ table = Table.new :users
188
+ manager = Arel::SelectManager.new engine
189
+ manager.from table
190
+ manager.insert 'VALUES(NULL)'
191
+
192
+ engine.executed.last.must_be_like %{
193
+ INSERT INTO "users" VALUES(NULL)
194
+ }
195
+ end
196
+ end
197
+
198
+ describe 'lock' do
199
+ # This should fail on other databases
200
+ it 'adds a lock node' do
201
+ table = Table.new :users
202
+ mgr = table.from table
203
+ mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" }
204
+ end
205
+ end
206
+
207
+ describe 'orders' do
208
+ it 'returns order clauses' do
209
+ table = Table.new :users
210
+ manager = Arel::SelectManager.new Table.engine
211
+ order = table[:id]
212
+ manager.order table[:id]
213
+ manager.orders.must_equal [order]
214
+ end
215
+ end
216
+
217
+ describe 'order' do
218
+ it 'generates order clauses' do
219
+ table = Table.new :users
220
+ manager = Arel::SelectManager.new Table.engine
221
+ manager.project SqlLiteral.new '*'
222
+ manager.from table
223
+ manager.order table[:id]
224
+ manager.to_sql.must_be_like %{
225
+ SELECT * FROM "users" ORDER BY "users"."id"
226
+ }
227
+ end
228
+
229
+ # FIXME: I would like to deprecate this
230
+ it 'takes *args' do
231
+ table = Table.new :users
232
+ manager = Arel::SelectManager.new Table.engine
233
+ manager.project SqlLiteral.new '*'
234
+ manager.from table
235
+ manager.order table[:id], table[:name]
236
+ manager.to_sql.must_be_like %{
237
+ SELECT * FROM "users" ORDER BY "users"."id", "users"."name"
238
+ }
239
+ end
240
+
241
+ it 'chains' do
242
+ table = Table.new :users
243
+ manager = Arel::SelectManager.new Table.engine
244
+ manager.order(table[:id]).must_equal manager
245
+ end
246
+ end
247
+
248
+ describe 'on' do
249
+ it 'takes two params' do
250
+ left = Table.new :users
251
+ right = left.alias
252
+ predicate = left[:id].eq(right[:id])
253
+ manager = Arel::SelectManager.new Table.engine
254
+
255
+ manager.from left
256
+ manager.join(right).on(predicate, predicate)
257
+ manager.to_sql.must_be_like %{
258
+ SELECT FROM "users"
259
+ INNER JOIN "users" "users_2"
260
+ ON "users"."id" = "users_2"."id" AND
261
+ "users"."id" = "users_2"."id"
262
+ }
263
+ end
264
+
265
+ it 'takes three params' do
266
+ left = Table.new :users
267
+ right = left.alias
268
+ predicate = left[:id].eq(right[:id])
269
+ manager = Arel::SelectManager.new Table.engine
270
+
271
+ manager.from left
272
+ manager.join(right).on(
273
+ predicate,
274
+ predicate,
275
+ left[:name].eq(right[:name])
276
+ )
277
+ manager.to_sql.must_be_like %{
278
+ SELECT FROM "users"
279
+ INNER JOIN "users" "users_2"
280
+ ON "users"."id" = "users_2"."id" AND
281
+ "users"."id" = "users_2"."id" AND
282
+ "users"."name" = "users_2"."name"
283
+ }
284
+ end
285
+ end
286
+
287
+ describe 'join' do
288
+ it 'responds to join' do
289
+ left = Table.new :users
290
+ right = left.alias
291
+ predicate = left[:id].eq(right[:id])
292
+ manager = Arel::SelectManager.new Table.engine
293
+
294
+ manager.from left
295
+ manager.join(right).on(predicate)
296
+ manager.to_sql.must_be_like %{
297
+ SELECT FROM "users"
298
+ INNER JOIN "users" "users_2"
299
+ ON "users"."id" = "users_2"."id"
300
+ }
301
+ end
302
+
303
+ it 'takes a class' do
304
+ left = Table.new :users
305
+ right = left.alias
306
+ predicate = left[:id].eq(right[:id])
307
+ manager = Arel::SelectManager.new Table.engine
308
+
309
+ manager.from left
310
+ manager.join(right, Nodes::OuterJoin).on(predicate)
311
+ manager.to_sql.must_be_like %{
312
+ SELECT FROM "users"
313
+ LEFT OUTER JOIN "users" "users_2"
314
+ ON "users"."id" = "users_2"."id"
315
+ }
316
+ end
317
+
318
+ it 'noops on nil' do
319
+ manager = Arel::SelectManager.new Table.engine
320
+ manager.join(nil).must_equal manager
321
+ end
322
+ end
323
+
324
+ describe 'joins' do
325
+ it 'returns join sql' do
326
+ table = Table.new :users
327
+ aliaz = table.alias
328
+ manager = Arel::SelectManager.new Table.engine
329
+ manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
330
+ manager.join_sql.must_be_like %{
331
+ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"
332
+ }
333
+ manager.joins(manager).must_equal manager.join_sql
334
+ end
335
+
336
+ it 'returns outer join sql' do
337
+ table = Table.new :users
338
+ aliaz = table.alias
339
+ manager = Arel::SelectManager.new Table.engine
340
+ manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
341
+ manager.join_sql.must_be_like %{
342
+ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"
343
+ }
344
+ manager.joins(manager).must_equal manager.join_sql
345
+ end
346
+
347
+ it 'returns string join sql' do
348
+ table = Table.new :users
349
+ manager = Arel::SelectManager.new Table.engine
350
+ manager.from Nodes::StringJoin.new(table, 'hello')
351
+ manager.join_sql.must_be_like %{ 'hello' }
352
+ manager.joins(manager).must_equal manager.join_sql
353
+ end
354
+
355
+ it 'returns nil join sql' do
356
+ manager = Arel::SelectManager.new Table.engine
357
+ manager.join_sql.must_be_nil
358
+ end
359
+ end
360
+
361
+ describe 'order_clauses' do
362
+ it 'returns order clauses as a list' do
363
+ table = Table.new :users
364
+ manager = Arel::SelectManager.new Table.engine
365
+ manager.from table
366
+ manager.order table[:id]
367
+ manager.order_clauses.first.must_be_like %{ "users"."id" }
368
+ end
369
+ end
370
+
371
+ describe 'group' do
372
+ it 'takes an attribute' do
373
+ table = Table.new :users
374
+ manager = Arel::SelectManager.new Table.engine
375
+ manager.from table
376
+ manager.group table[:id]
377
+ manager.to_sql.must_be_like %{
378
+ SELECT FROM "users" GROUP BY "users"."id"
379
+ }
380
+ end
381
+
382
+ it 'chains' do
383
+ table = Table.new :users
384
+ manager = Arel::SelectManager.new Table.engine
385
+ manager.group(table[:id]).must_equal manager
386
+ end
387
+
388
+ it 'takes multiple args' do
389
+ table = Table.new :users
390
+ manager = Arel::SelectManager.new Table.engine
391
+ manager.from table
392
+ manager.group table[:id], table[:name]
393
+ manager.to_sql.must_be_like %{
394
+ SELECT FROM "users" GROUP BY "users"."id", "users"."name"
395
+ }
396
+ end
397
+
398
+ # FIXME: backwards compat
399
+ it 'makes strings literals' do
400
+ table = Table.new :users
401
+ manager = Arel::SelectManager.new Table.engine
402
+ manager.from table
403
+ manager.group 'foo'
404
+ manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
405
+ end
406
+ end
407
+
408
+ describe 'delete' do
409
+ it "copies from" do
410
+ engine = EngineProxy.new Table.engine
411
+ table = Table.new :users
412
+ manager = Arel::SelectManager.new engine
413
+ manager.from table
414
+ manager.delete
415
+
416
+ engine.executed.last.must_be_like %{ DELETE FROM "users" }
417
+ end
418
+
419
+ it "copies where" do
420
+ engine = EngineProxy.new Table.engine
421
+ table = Table.new :users
422
+ manager = Arel::SelectManager.new engine
423
+ manager.from table
424
+ manager.where table[:id].eq 10
425
+ manager.delete
426
+
427
+ engine.executed.last.must_be_like %{
428
+ DELETE FROM "users" WHERE "users"."id" = 10
429
+ }
430
+ end
431
+ end
432
+
433
+ describe 'where_sql' do
434
+ it 'gives me back the where sql' do
435
+ table = Table.new :users
436
+ manager = Arel::SelectManager.new Table.engine
437
+ manager.from table
438
+ manager.where table[:id].eq 10
439
+ manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 }
440
+ end
441
+
442
+ it 'returns nil when there are no wheres' do
443
+ table = Table.new :users
444
+ manager = Arel::SelectManager.new Table.engine
445
+ manager.from table
446
+ manager.where_sql.must_be_nil
447
+ end
448
+ end
449
+
450
+ describe 'update' do
451
+ it 'copies limits' do
452
+ engine = EngineProxy.new Table.engine
453
+ table = Table.new :users
454
+ manager = Arel::SelectManager.new engine
455
+ manager.from table
456
+ manager.take 1
457
+ manager.update(SqlLiteral.new('foo = bar'))
458
+
459
+ engine.executed.last.must_be_like %{
460
+ UPDATE "users" SET foo = bar
461
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1)
462
+ }
463
+ end
464
+
465
+ it 'copies order' do
466
+ engine = EngineProxy.new Table.engine
467
+ table = Table.new :users
468
+ manager = Arel::SelectManager.new engine
469
+ manager.from table
470
+ manager.order :foo
471
+ manager.update(SqlLiteral.new('foo = bar'))
472
+
473
+ engine.executed.last.must_be_like %{
474
+ UPDATE "users" SET foo = bar
475
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo)
476
+ }
477
+ end
478
+
479
+ it 'takes a string' do
480
+ engine = EngineProxy.new Table.engine
481
+ table = Table.new :users
482
+ manager = Arel::SelectManager.new engine
483
+ manager.from table
484
+ manager.update(SqlLiteral.new('foo = bar'))
485
+
486
+ engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar }
487
+ end
488
+
489
+ it 'copies where clauses' do
490
+ engine = EngineProxy.new Table.engine
491
+ table = Table.new :users
492
+ manager = Arel::SelectManager.new engine
493
+ manager.where table[:id].eq 10
494
+ manager.from table
495
+ manager.update(table[:id] => 1)
496
+
497
+ engine.executed.last.must_be_like %{
498
+ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10
499
+ }
500
+ end
501
+
502
+ it 'executes an update statement' do
503
+ engine = EngineProxy.new Table.engine
504
+ table = Table.new :users
505
+ manager = Arel::SelectManager.new engine
506
+ manager.from table
507
+ manager.update(table[:id] => 1)
508
+
509
+ engine.executed.last.must_be_like %{
510
+ UPDATE "users" SET "id" = 1
511
+ }
512
+ end
513
+ end
514
+
515
+ describe 'project' do
516
+ it 'takes multiple args' do
517
+ manager = Arel::SelectManager.new Table.engine
518
+ manager.project Nodes::SqlLiteral.new('foo'),
519
+ Nodes::SqlLiteral.new('bar')
520
+ manager.to_sql.must_be_like %{ SELECT foo, bar }
521
+ end
522
+
523
+ it 'takes strings' do
524
+ manager = Arel::SelectManager.new Table.engine
525
+ manager.project Nodes::SqlLiteral.new('*')
526
+ manager.to_sql.must_be_like %{ SELECT * }
527
+ end
528
+
529
+ it "takes sql literals" do
530
+ manager = Arel::SelectManager.new Table.engine
531
+ manager.project Nodes::SqlLiteral.new '*'
532
+ manager.to_sql.must_be_like %{
533
+ SELECT *
534
+ }
535
+ end
536
+ end
537
+
538
+ describe 'take' do
539
+ it "knows take" do
540
+ table = Table.new :users
541
+ manager = Arel::SelectManager.new Table.engine
542
+ manager.from(table).project(table['id'])
543
+ manager.where(table['id'].eq(1))
544
+ manager.take 1
545
+
546
+ manager.to_sql.must_be_like %{
547
+ SELECT "users"."id"
548
+ FROM "users"
549
+ WHERE "users"."id" = 1
550
+ LIMIT 1
551
+ }
552
+ end
553
+
554
+ it "chains" do
555
+ manager = Arel::SelectManager.new Table.engine
556
+ manager.take(1).must_equal manager
557
+ end
558
+ end
559
+
560
+ describe 'where' do
561
+ it "knows where" do
562
+ table = Table.new :users
563
+ manager = Arel::SelectManager.new Table.engine
564
+ manager.from(table).project(table['id'])
565
+ manager.where(table['id'].eq(1))
566
+ manager.to_sql.must_be_like %{
567
+ SELECT "users"."id"
568
+ FROM "users"
569
+ WHERE "users"."id" = 1
570
+ }
571
+ end
572
+
573
+ it "chains" do
574
+ table = Table.new :users
575
+ manager = Arel::SelectManager.new Table.engine
576
+ manager.from(table)
577
+ manager.project(table['id']).where(table['id'].eq 1).must_equal manager
578
+ end
579
+ end
580
+
581
+ describe "join" do
582
+ it "joins itself" do
583
+ left = Table.new :users
584
+ right = left.alias
585
+ predicate = left[:id].eq(right[:id])
586
+
587
+ mgr = left.join(right)
588
+ mgr.project Nodes::SqlLiteral.new('*')
589
+ mgr.on(predicate).must_equal mgr
590
+
591
+ mgr.to_sql.must_be_like %{
592
+ SELECT * FROM "users"
593
+ INNER JOIN "users" "users_2"
594
+ ON "users"."id" = "users_2"."id"
595
+ }
596
+ end
597
+ end
598
+
599
+ describe 'from' do
600
+ it "makes sql" do
601
+ table = Table.new :users
602
+ manager = Arel::SelectManager.new Table.engine
603
+
604
+ manager.from table
605
+ manager.project table['id']
606
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
607
+ end
608
+
609
+ it "chains" do
610
+ table = Table.new :users
611
+ manager = Arel::SelectManager.new Table.engine
612
+ manager.from(table).project(table['id']).must_equal manager
613
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
614
+ end
615
+ end
616
+ end
617
+
618
+ describe 'set operations' do
619
+ before do
620
+ @table = Table.new :users
621
+ @m1 = Arel::SelectManager.new Table.engine, @table
622
+ @m1.project Arel.sql('*')
623
+ @m2 = Arel::SelectManager.new Table.engine, @table
624
+ @m2.project Arel.sql('*')
625
+ end
626
+
627
+ it 'supports union' do
628
+ @m1.where(@table[:id].lt(18))
629
+ @m2.where(@table[:id].gt(99))
630
+ (@m1.union @m2).to_sql.must_be_like %{
631
+ ( SELECT * FROM "users" WHERE "users"."id" < 18 UNION SELECT * FROM "users" WHERE "users"."id" > 99 )
632
+ }
633
+ end
634
+
635
+ it 'supports union all' do
636
+ @m1.where(@table[:id].lt(18))
637
+ @m2.where(@table[:id].gt(99))
638
+ (@m1.union :all, @m2).to_sql.must_be_like %{
639
+ ( SELECT * FROM "users" WHERE "users"."id" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."id" > 99 )
640
+ }
641
+ end
642
+
643
+ it 'supports intersect' do
644
+ @m1.where(@table[:id].gt(18))
645
+ @m2.where(@table[:id].lt(99))
646
+ (@m1.intersect @m2).to_sql.must_be_like %{
647
+ ( SELECT * FROM "users" WHERE "users"."id" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."id" < 99 )
648
+ }
649
+ end
650
+
651
+ it 'supports except' do
652
+ @m1.where(@table[:id].in(18..60))
653
+ @m2.where(@table[:id].in(40..99))
654
+ (@m1.except @m2).to_sql.must_be_like %{
655
+ ( SELECT * FROM "users" WHERE "users"."id" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."id" BETWEEN 40 AND 99 )
656
+ }
657
+ end
658
+ end
659
+ end