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,122 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the postgres visitor' do
6
- before do
7
- @visitor = PostgreSQL.new Table.engine.connection
8
- @table = Table.new(:users)
9
- @attr = @table[:id]
10
- end
11
-
12
- def compile node
13
- @visitor.accept(node, Collectors::SQLString.new).value
14
- end
15
-
16
- describe 'locking' do
17
- it 'defaults to FOR UPDATE' do
18
- compile(Nodes::Lock.new(Arel.sql('FOR UPDATE'))).must_be_like %{
19
- FOR UPDATE
20
- }
21
- end
22
-
23
- it 'allows a custom string to be used as a lock' do
24
- node = Nodes::Lock.new(Arel.sql('FOR SHARE'))
25
- compile(node).must_be_like %{
26
- FOR SHARE
27
- }
28
- end
29
- end
30
-
31
- it "should escape LIMIT" do
32
- sc = Arel::Nodes::SelectStatement.new
33
- sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg"))
34
- sc.cores.first.projections << Arel.sql('DISTINCT ON')
35
- sc.orders << Arel.sql("xyz")
36
- sql = compile(sc)
37
- assert_match(/LIMIT 'omg'/, sql)
38
- assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit'
39
- end
40
-
41
- it 'should support DISTINCT ON' do
42
- core = Arel::Nodes::SelectCore.new
43
- core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron'))
44
- assert_match 'DISTINCT ON ( aaron )', compile(core)
45
- end
46
-
47
- it 'should support DISTINCT' do
48
- core = Arel::Nodes::SelectCore.new
49
- core.set_quantifier = Arel::Nodes::Distinct.new
50
- assert_equal 'SELECT DISTINCT', compile(core)
51
- end
52
-
53
- describe "Nodes::Matches" do
54
- it "should know how to visit" do
55
- node = @table[:name].matches('foo%')
56
- compile(node).must_be_like %{
57
- "users"."name" ILIKE 'foo%'
58
- }
59
- end
60
-
61
- it 'can handle subqueries' do
62
- subquery = @table.project(:id).where(@table[:name].matches('foo%'))
63
- node = @attr.in subquery
64
- compile(node).must_be_like %{
65
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%')
66
- }
67
- end
68
- end
69
-
70
- describe "Nodes::DoesNotMatch" do
71
- it "should know how to visit" do
72
- node = @table[:name].does_not_match('foo%')
73
- compile(node).must_be_like %{
74
- "users"."name" NOT ILIKE 'foo%'
75
- }
76
- end
77
-
78
- it 'can handle subqueries' do
79
- subquery = @table.project(:id).where(@table[:name].does_not_match('foo%'))
80
- node = @attr.in subquery
81
- compile(node).must_be_like %{
82
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT ILIKE 'foo%')
83
- }
84
- end
85
- end
86
-
87
- describe "Nodes::Regexp" do
88
- it "should know how to visit" do
89
- node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))
90
- compile(node).must_be_like %{
91
- "users"."name" ~ 'foo%'
92
- }
93
- end
94
-
95
- it 'can handle subqueries' do
96
- subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')))
97
- node = @attr.in subquery
98
- compile(node).must_be_like %{
99
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%')
100
- }
101
- end
102
- end
103
-
104
- describe "Nodes::NotRegexp" do
105
- it "should know how to visit" do
106
- node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))
107
- compile(node).must_be_like %{
108
- "users"."name" !~ 'foo%'
109
- }
110
- end
111
-
112
- it 'can handle subqueries' do
113
- subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')))
114
- node = @attr.in subquery
115
- compile(node).must_be_like %{
116
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%')
117
- }
118
- end
119
- end
120
- end
121
- end
122
- end
@@ -1,23 +0,0 @@
1
- require 'helper'
2
-
3
- module Arel
4
- module Visitors
5
- describe 'the sqlite visitor' do
6
- before do
7
- @visitor = SQLite.new Table.engine.connection_pool
8
- end
9
-
10
- it 'defaults limit to -1' do
11
- stmt = Nodes::SelectStatement.new
12
- stmt.offset = Nodes::Offset.new(1)
13
- sql = @visitor.accept(stmt, Collectors::SQLString.new).value
14
- sql.must_be_like "SELECT LIMIT -1 OFFSET 1"
15
- end
16
-
17
- it 'does not support locking' do
18
- node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
19
- assert_equal '', @visitor.accept(node, Collectors::SQLString.new).value
20
- end
21
- end
22
- end
23
- end
@@ -1,598 +0,0 @@
1
- require 'helper'
2
- require 'set'
3
-
4
- module Arel
5
- module Visitors
6
- describe 'the to_sql visitor' do
7
- before do
8
- @conn = FakeRecord::Base.new
9
- @visitor = ToSql.new @conn.connection
10
- @table = Table.new(:users)
11
- @attr = @table[:id]
12
- end
13
-
14
- def compile node
15
- @visitor.accept(node, Collectors::SQLString.new).value
16
- end
17
-
18
- it 'works with BindParams' do
19
- node = Nodes::BindParam.new 'omg'
20
- sql = compile node
21
- sql.must_be_like 'omg'
22
- end
23
-
24
- it 'can define a dispatch method' do
25
- visited = false
26
- viz = Class.new(Arel::Visitors::Reduce) {
27
- define_method(:hello) do |node, c|
28
- visited = true
29
- end
30
-
31
- def dispatch
32
- { Arel::Table.name => 'hello' }
33
- end
34
- }.new
35
-
36
- viz.accept(@table, Collectors::SQLString.new)
37
- assert visited, 'hello method was called'
38
- end
39
-
40
- it 'should not quote sql literals' do
41
- node = @table[Arel.star]
42
- sql = compile node
43
- sql.must_be_like '"users".*'
44
- end
45
-
46
- it 'should visit named functions' do
47
- function = Nodes::NamedFunction.new('omg', [Arel.star])
48
- assert_equal 'omg(*)', compile(function)
49
- end
50
-
51
- it 'should chain predications on named functions' do
52
- function = Nodes::NamedFunction.new('omg', [Arel.star])
53
- sql = compile(function.eq(2))
54
- sql.must_be_like %{ omg(*) = 2 }
55
- end
56
-
57
- it 'should visit built-in functions' do
58
- function = Nodes::Count.new([Arel.star])
59
- assert_equal 'COUNT(*)', compile(function)
60
-
61
- function = Nodes::Sum.new([Arel.star])
62
- assert_equal 'SUM(*)', compile(function)
63
-
64
- function = Nodes::Max.new([Arel.star])
65
- assert_equal 'MAX(*)', compile(function)
66
-
67
- function = Nodes::Min.new([Arel.star])
68
- assert_equal 'MIN(*)', compile(function)
69
-
70
- function = Nodes::Avg.new([Arel.star])
71
- assert_equal 'AVG(*)', compile(function)
72
- end
73
-
74
- it 'should visit built-in functions operating on distinct values' do
75
- function = Nodes::Count.new([Arel.star])
76
- function.distinct = true
77
- assert_equal 'COUNT(DISTINCT *)', compile(function)
78
-
79
- function = Nodes::Sum.new([Arel.star])
80
- function.distinct = true
81
- assert_equal 'SUM(DISTINCT *)', compile(function)
82
-
83
- function = Nodes::Max.new([Arel.star])
84
- function.distinct = true
85
- assert_equal 'MAX(DISTINCT *)', compile(function)
86
-
87
- function = Nodes::Min.new([Arel.star])
88
- function.distinct = true
89
- assert_equal 'MIN(DISTINCT *)', compile(function)
90
-
91
- function = Nodes::Avg.new([Arel.star])
92
- function.distinct = true
93
- assert_equal 'AVG(DISTINCT *)', compile(function)
94
- end
95
-
96
- it 'works with lists' do
97
- function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star])
98
- assert_equal 'omg(*, *)', compile(function)
99
- end
100
-
101
- describe 'Nodes::Equality' do
102
- it "should escape strings" do
103
- test = Table.new(:users)[:name].eq 'Aaron Patterson'
104
- compile(test).must_be_like %{
105
- "users"."name" = 'Aaron Patterson'
106
- }
107
- end
108
-
109
- it 'should handle false' do
110
- table = Table.new(:users)
111
- val = Nodes.build_quoted(false, table[:active])
112
- sql = compile Nodes::Equality.new(val, val)
113
- sql.must_be_like %{ 'f' = 'f' }
114
- end
115
-
116
- it 'should use the column to quote' do
117
- table = Table.new(:users)
118
- val = Nodes.build_quoted('1-fooo', table[:id])
119
- sql = compile Nodes::Equality.new(table[:id], val)
120
- sql.must_be_like %{ "users"."id" = 1 }
121
- end
122
-
123
- it 'should use the column to quote integers' do
124
- table = Table.new(:users)
125
- sql = compile table[:name].eq(0)
126
- sql.must_be_like %{ "users"."name" = '0' }
127
- end
128
-
129
- it 'should handle nil' do
130
- sql = compile Nodes::Equality.new(@table[:name], nil)
131
- sql.must_be_like %{ "users"."name" IS NULL }
132
- end
133
- end
134
-
135
- describe 'Nodes::Grouping' do
136
- it 'wraps nested groupings in brackets only once' do
137
- sql = compile Nodes::Grouping.new(Nodes::Grouping.new(Nodes.build_quoted('foo')))
138
- sql.must_equal "('foo')"
139
- end
140
- end
141
-
142
- describe 'Nodes::NotEqual' do
143
- it 'should handle false' do
144
- val = Nodes.build_quoted(false, @table[:active])
145
- sql = compile Nodes::NotEqual.new(@table[:active], val)
146
- sql.must_be_like %{ "users"."active" != 'f' }
147
- end
148
-
149
- it 'should handle nil' do
150
- val = Nodes.build_quoted(nil, @table[:active])
151
- sql = compile Nodes::NotEqual.new(@table[:name], val)
152
- sql.must_be_like %{ "users"."name" IS NOT NULL }
153
- end
154
- end
155
-
156
- it "should visit string subclass" do
157
- [
158
- Class.new(String).new(":'("),
159
- Class.new(Class.new(String)).new(":'("),
160
- ].each do |obj|
161
- val = Nodes.build_quoted(obj, @table[:active])
162
- sql = compile Nodes::NotEqual.new(@table[:name], val)
163
- sql.must_be_like %{ "users"."name" != ':\\'(' }
164
- end
165
- end
166
-
167
- it "should visit_Class" do
168
- compile(Nodes.build_quoted(DateTime)).must_equal "'DateTime'"
169
- end
170
-
171
- it "should escape LIMIT" do
172
- sc = Arel::Nodes::SelectStatement.new
173
- sc.limit = Arel::Nodes::Limit.new(Nodes.build_quoted("omg"))
174
- assert_match(/LIMIT 'omg'/, compile(sc))
175
- end
176
-
177
- it "should quote LIMIT without column type coercion" do
178
- table = Table.new(:users)
179
- sc = table.where(table[:name].eq(0)).take(1).ast
180
- assert_match(/WHERE "users"."name" = '0' LIMIT 1/, compile(sc))
181
- end
182
-
183
- it "should visit_DateTime" do
184
- called_with = nil
185
- @conn.connection.extend(Module.new {
186
- define_method(:quote) do |thing, column|
187
- called_with = column
188
- super(thing, column)
189
- end
190
- })
191
-
192
- dt = DateTime.now
193
- table = Table.new(:users)
194
- test = table[:created_at].eq dt
195
- sql = compile test
196
-
197
- assert_equal "created_at", called_with.name
198
- sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d %H:%M:%S")}'}
199
- end
200
-
201
- it "should visit_Float" do
202
- test = Table.new(:products)[:price].eq 2.14
203
- sql = compile test
204
- sql.must_be_like %{"products"."price" = 2.14}
205
- end
206
-
207
- it "should visit_Not" do
208
- sql = compile Nodes::Not.new(Arel.sql("foo"))
209
- sql.must_be_like "NOT (foo)"
210
- end
211
-
212
- it "should apply Not to the whole expression" do
213
- node = Nodes::And.new [@attr.eq(10), @attr.eq(11)]
214
- sql = compile Nodes::Not.new(node)
215
- sql.must_be_like %{NOT ("users"."id" = 10 AND "users"."id" = 11)}
216
- end
217
-
218
- it "should visit_As" do
219
- as = Nodes::As.new(Arel.sql("foo"), Arel.sql("bar"))
220
- sql = compile as
221
- sql.must_be_like "foo AS bar"
222
- end
223
-
224
- it "should visit_Bignum" do
225
- compile 8787878092
226
- end
227
-
228
- it "should visit_Hash" do
229
- compile(Nodes.build_quoted({:a => 1}))
230
- end
231
-
232
- it "should visit_Set" do
233
- compile Nodes.build_quoted(Set.new([1, 2]))
234
- end
235
-
236
- it "should visit_BigDecimal" do
237
- compile Nodes.build_quoted(BigDecimal.new('2.14'))
238
- end
239
-
240
- it "should visit_Date" do
241
- called_with = nil
242
- @conn.connection.extend(Module.new {
243
- define_method(:quote) do |thing, column|
244
- called_with = column
245
- super(thing, column)
246
- end
247
- })
248
-
249
- dt = Date.today
250
- table = Table.new(:users)
251
- test = table[:created_at].eq dt
252
- sql = compile test
253
-
254
- assert_equal "created_at", called_with.name
255
- sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d")}'}
256
- end
257
-
258
- it "should visit_NilClass" do
259
- compile(Nodes.build_quoted(nil)).must_be_like "NULL"
260
- end
261
-
262
- it "unsupported input should not raise ArgumentError" do
263
- error = assert_raises(RuntimeError) { compile(nil) }
264
- assert_match(/\Aunsupported/, error.message)
265
- end
266
-
267
- it "should visit_Arel_SelectManager, which is a subquery" do
268
- mgr = Table.new(:foo).project(:bar)
269
- compile(mgr).must_be_like '(SELECT bar FROM "foo")'
270
- end
271
-
272
- it "should visit_Arel_Nodes_And" do
273
- node = Nodes::And.new [@attr.eq(10), @attr.eq(11)]
274
- compile(node).must_be_like %{
275
- "users"."id" = 10 AND "users"."id" = 11
276
- }
277
- end
278
-
279
- it "should visit_Arel_Nodes_Or" do
280
- node = Nodes::Or.new @attr.eq(10), @attr.eq(11)
281
- compile(node).must_be_like %{
282
- "users"."id" = 10 OR "users"."id" = 11
283
- }
284
- end
285
-
286
- it "should visit_Arel_Nodes_Assignment" do
287
- column = @table["id"]
288
- node = Nodes::Assignment.new(
289
- Nodes::UnqualifiedColumn.new(column),
290
- Nodes::UnqualifiedColumn.new(column)
291
- )
292
- compile(node).must_be_like %{
293
- "id" = "id"
294
- }
295
- end
296
-
297
- it "should visit visit_Arel_Attributes_Time" do
298
- attr = Attributes::Time.new(@attr.relation, @attr.name)
299
- compile attr
300
- end
301
-
302
- it "should visit_TrueClass" do
303
- test = Table.new(:users)[:bool].eq(true)
304
- compile(test).must_be_like %{ "users"."bool" = 't' }
305
- end
306
-
307
- describe "Nodes::Matches" do
308
- it "should know how to visit" do
309
- node = @table[:name].matches('foo%')
310
- compile(node).must_be_like %{
311
- "users"."name" LIKE 'foo%'
312
- }
313
- end
314
-
315
- it "can handle ESCAPE" do
316
- node = @table[:name].matches('foo!%', '!')
317
- compile(node).must_be_like %{
318
- "users"."name" LIKE 'foo!%' ESCAPE '!'
319
- }
320
- end
321
-
322
- it 'can handle subqueries' do
323
- subquery = @table.project(:id).where(@table[:name].matches('foo%'))
324
- node = @attr.in subquery
325
- compile(node).must_be_like %{
326
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" LIKE 'foo%')
327
- }
328
- end
329
- end
330
-
331
- describe "Nodes::DoesNotMatch" do
332
- it "should know how to visit" do
333
- node = @table[:name].does_not_match('foo%')
334
- compile(node).must_be_like %{
335
- "users"."name" NOT LIKE 'foo%'
336
- }
337
- end
338
-
339
- it "can handle ESCAPE" do
340
- node = @table[:name].does_not_match('foo!%', '!')
341
- compile(node).must_be_like %{
342
- "users"."name" NOT LIKE 'foo!%' ESCAPE '!'
343
- }
344
- end
345
-
346
- it 'can handle subqueries' do
347
- subquery = @table.project(:id).where(@table[:name].does_not_match('foo%'))
348
- node = @attr.in subquery
349
- compile(node).must_be_like %{
350
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT LIKE 'foo%')
351
- }
352
- end
353
- end
354
-
355
- describe "Nodes::Ordering" do
356
- it "should know how to visit" do
357
- node = @attr.desc
358
- compile(node).must_be_like %{
359
- "users"."id" DESC
360
- }
361
- end
362
- end
363
-
364
- describe "Nodes::In" do
365
- it "should know how to visit" do
366
- node = @attr.in [1, 2, 3]
367
- compile(node).must_be_like %{
368
- "users"."id" IN (1, 2, 3)
369
- }
370
- end
371
-
372
- it "should return 1=0 when empty right which is always false" do
373
- node = @attr.in []
374
- compile(node).must_equal '1=0'
375
- end
376
-
377
- it 'can handle two dot ranges' do
378
- node = @attr.between 1..3
379
- compile(node).must_be_like %{
380
- "users"."id" BETWEEN 1 AND 3
381
- }
382
- end
383
-
384
- it 'can handle three dot ranges' do
385
- node = @attr.between 1...3
386
- compile(node).must_be_like %{
387
- "users"."id" >= 1 AND "users"."id" < 3
388
- }
389
- end
390
-
391
- it 'can handle ranges bounded by infinity' do
392
- node = @attr.between 1..Float::INFINITY
393
- compile(node).must_be_like %{
394
- "users"."id" >= 1
395
- }
396
- node = @attr.between(-Float::INFINITY..3)
397
- compile(node).must_be_like %{
398
- "users"."id" <= 3
399
- }
400
- node = @attr.between(-Float::INFINITY...3)
401
- compile(node).must_be_like %{
402
- "users"."id" < 3
403
- }
404
- node = @attr.between(-Float::INFINITY..Float::INFINITY)
405
- compile(node).must_be_like %{1=1}
406
- end
407
-
408
- it 'can handle subqueries' do
409
- table = Table.new(:users)
410
- subquery = table.project(:id).where(table[:name].eq('Aaron'))
411
- node = @attr.in subquery
412
- compile(node).must_be_like %{
413
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron')
414
- }
415
- end
416
-
417
- it 'uses the same column for escaping values' do
418
- @attr = Table.new(:users)[:name]
419
- visitor = Class.new(ToSql) do
420
- attr_accessor :expected
421
-
422
- def quote value, column = nil
423
- raise unless column == expected
424
- super
425
- end
426
- end
427
- vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) }
428
- in_node = Nodes::In.new @attr, vals
429
- visitor = visitor.new(Table.engine.connection)
430
- visitor.expected = Table.engine.connection.columns(:users).find { |x|
431
- x.name == 'name'
432
- }
433
- visitor.accept(in_node, Collectors::SQLString.new).value.must_equal %("users"."name" IN ('a', 'b', 'c'))
434
- end
435
- end
436
-
437
- describe "Nodes::InfixOperation" do
438
- it "should handle Multiplication" do
439
- node = Arel::Attributes::Decimal.new(Table.new(:products), :price) * Arel::Attributes::Decimal.new(Table.new(:currency_rates), :rate)
440
- compile(node).must_equal %("products"."price" * "currency_rates"."rate")
441
- end
442
-
443
- it "should handle Division" do
444
- node = Arel::Attributes::Decimal.new(Table.new(:products), :price) / 5
445
- compile(node).must_equal %("products"."price" / 5)
446
- end
447
-
448
- it "should handle Addition" do
449
- node = Arel::Attributes::Decimal.new(Table.new(:products), :price) + 6
450
- compile(node).must_equal %(("products"."price" + 6))
451
- end
452
-
453
- it "should handle Subtraction" do
454
- node = Arel::Attributes::Decimal.new(Table.new(:products), :price) - 7
455
- compile(node).must_equal %(("products"."price" - 7))
456
- end
457
-
458
- it "should handle arbitrary operators" do
459
- node = Arel::Nodes::InfixOperation.new(
460
- '||',
461
- Arel::Attributes::String.new(Table.new(:products), :name),
462
- Arel::Attributes::String.new(Table.new(:products), :name)
463
- )
464
- compile(node).must_equal %("products"."name" || "products"."name")
465
- end
466
- end
467
-
468
- describe "Nodes::NotIn" do
469
- it "should know how to visit" do
470
- node = @attr.not_in [1, 2, 3]
471
- compile(node).must_be_like %{
472
- "users"."id" NOT IN (1, 2, 3)
473
- }
474
- end
475
-
476
- it "should return 1=1 when empty right which is always true" do
477
- node = @attr.not_in []
478
- compile(node).must_equal '1=1'
479
- end
480
-
481
- it 'can handle two dot ranges' do
482
- node = @attr.not_between 1..3
483
- compile(node).must_equal(
484
- %{("users"."id" < 1 OR "users"."id" > 3)}
485
- )
486
- end
487
-
488
- it 'can handle three dot ranges' do
489
- node = @attr.not_between 1...3
490
- compile(node).must_equal(
491
- %{("users"."id" < 1 OR "users"."id" >= 3)}
492
- )
493
- end
494
-
495
- it 'can handle ranges bounded by infinity' do
496
- node = @attr.not_between 1..Float::INFINITY
497
- compile(node).must_be_like %{
498
- "users"."id" < 1
499
- }
500
- node = @attr.not_between(-Float::INFINITY..3)
501
- compile(node).must_be_like %{
502
- "users"."id" > 3
503
- }
504
- node = @attr.not_between(-Float::INFINITY...3)
505
- compile(node).must_be_like %{
506
- "users"."id" >= 3
507
- }
508
- node = @attr.not_between(-Float::INFINITY..Float::INFINITY)
509
- compile(node).must_be_like %{1=0}
510
- end
511
-
512
- it 'can handle subqueries' do
513
- table = Table.new(:users)
514
- subquery = table.project(:id).where(table[:name].eq('Aaron'))
515
- node = @attr.not_in subquery
516
- compile(node).must_be_like %{
517
- "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron')
518
- }
519
- end
520
-
521
- it 'uses the same column for escaping values' do
522
- @attr = Table.new(:users)[:name]
523
- visitor = Class.new(ToSql) do
524
- attr_accessor :expected
525
-
526
- def quote value, column = nil
527
- raise unless column == expected
528
- super
529
- end
530
- end
531
- vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) }
532
- in_node = Nodes::NotIn.new @attr, vals
533
- visitor = visitor.new(Table.engine.connection)
534
- visitor.expected = Table.engine.connection.columns(:users).find { |x|
535
- x.name == 'name'
536
- }
537
- compile(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c'))
538
- end
539
- end
540
-
541
- describe 'Constants' do
542
- it "should handle true" do
543
- test = Table.new(:users).create_true
544
- compile(test).must_be_like %{
545
- TRUE
546
- }
547
- end
548
-
549
- it "should handle false" do
550
- test = Table.new(:users).create_false
551
- compile(test).must_be_like %{
552
- FALSE
553
- }
554
- end
555
- end
556
-
557
- describe 'TableAlias' do
558
- it "should use the underlying table for checking columns" do
559
- test = Table.new(:users).alias('zomgusers')[:id].eq '3'
560
- compile(test).must_be_like %{
561
- "zomgusers"."id" = 3
562
- }
563
- end
564
- end
565
-
566
- describe 'distinct on' do
567
- it 'raises not implemented error' do
568
- core = Arel::Nodes::SelectCore.new
569
- core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron'))
570
-
571
- assert_raises(NotImplementedError) do
572
- compile(core)
573
- end
574
- end
575
- end
576
-
577
- describe 'Nodes::Regexp' do
578
- it 'raises not implemented error' do
579
- node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))
580
-
581
- assert_raises(NotImplementedError) do
582
- compile(node)
583
- end
584
- end
585
- end
586
-
587
- describe 'Nodes::NotRegexp' do
588
- it 'raises not implemented error' do
589
- node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))
590
-
591
- assert_raises(NotImplementedError) do
592
- compile(node)
593
- end
594
- end
595
- end
596
- end
597
- end
598
- end