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,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