arel_extensions 2.0.4 → 2.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +54 -86
  3. data/README.md +1 -1
  4. data/Rakefile +13 -2
  5. data/arel_extensions.gemspec +1 -1
  6. data/gemfiles/rails4.gemfile +1 -1
  7. data/gemfiles/rails6.gemfile +1 -1
  8. data/generate_gems.sh +4 -3
  9. data/lib/arel_extensions.rb +33 -19
  10. data/lib/arel_extensions/attributes.rb +0 -1
  11. data/lib/arel_extensions/boolean_functions.rb +39 -12
  12. data/lib/arel_extensions/insert_manager.rb +7 -5
  13. data/lib/arel_extensions/nodes/abs.rb +0 -0
  14. data/lib/arel_extensions/nodes/case.rb +1 -1
  15. data/lib/arel_extensions/nodes/ceil.rb +0 -0
  16. data/lib/arel_extensions/nodes/coalesce.rb +0 -0
  17. data/lib/arel_extensions/nodes/concat.rb +0 -0
  18. data/lib/arel_extensions/nodes/duration.rb +0 -0
  19. data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
  20. data/lib/arel_extensions/nodes/floor.rb +0 -0
  21. data/lib/arel_extensions/nodes/function.rb +0 -0
  22. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  23. data/lib/arel_extensions/nodes/length.rb +0 -0
  24. data/lib/arel_extensions/nodes/locate.rb +0 -0
  25. data/lib/arel_extensions/nodes/rand.rb +0 -0
  26. data/lib/arel_extensions/nodes/replace.rb +0 -0
  27. data/lib/arel_extensions/nodes/round.rb +0 -0
  28. data/lib/arel_extensions/nodes/soundex.rb +0 -0
  29. data/lib/arel_extensions/nodes/substring.rb +0 -0
  30. data/lib/arel_extensions/nodes/trim.rb +0 -0
  31. data/lib/arel_extensions/nodes/union.rb +0 -0
  32. data/lib/arel_extensions/nodes/wday.rb +0 -0
  33. data/lib/arel_extensions/predications.rb +22 -19
  34. data/lib/arel_extensions/set_functions.rb +2 -2
  35. data/lib/arel_extensions/string_functions.rb +13 -0
  36. data/lib/arel_extensions/version.rb +1 -1
  37. data/lib/arel_extensions/visitors.rb +1 -1
  38. data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
  39. data/lib/arel_extensions/visitors/mysql.rb +24 -9
  40. data/lib/arel_extensions/visitors/oracle.rb +7 -8
  41. data/lib/arel_extensions/visitors/postgresql.rb +1 -1
  42. data/lib/arel_extensions/visitors/sqlite.rb +11 -7
  43. data/lib/arel_extensions/visitors/to_sql.rb +31 -38
  44. data/test/arelx_test_helper.rb +28 -0
  45. data/test/support/fake_record.rb +4 -0
  46. data/test/test_comparators.rb +8 -7
  47. data/test/visitors/test_bulk_insert_oracle.rb +4 -3
  48. data/test/visitors/test_bulk_insert_sqlite.rb +4 -3
  49. data/test/visitors/test_bulk_insert_to_sql.rb +3 -3
  50. data/test/visitors/test_oracle.rb +41 -41
  51. data/test/visitors/test_to_sql.rb +359 -206
  52. data/test/with_ar/all_agnostic_test.rb +18 -8
  53. data/test/with_ar/insert_agnostic_test.rb +1 -1
  54. data/test/with_ar/test_bulk_sqlite.rb +4 -3
  55. data/test/with_ar/test_math_sqlite.rb +1 -1
  56. data/test/with_ar/test_string_mysql.rb +1 -1
  57. data/test/with_ar/test_string_sqlite.rb +1 -1
  58. data/version_v1.rb +1 -1
  59. data/version_v2.rb +1 -1
  60. metadata +3 -3
  61. data/test/helper.rb +0 -18
@@ -1,6 +1,6 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::ToSql.class_eval do
3
+ class Arel::Visitors::ToSql
4
4
  Arel::Visitors::ToSql::COMMA = ', ' unless defined?(Arel::Visitors::ToSql::COMMA)
5
5
 
6
6
  # Math Functions
@@ -428,16 +428,15 @@ module ArelExtensions
428
428
  row_nb = o.left.length
429
429
  o.left.each_with_index do |row, idx|
430
430
  collector << '('
431
- v = Arel::Nodes::Values.new(row, o.cols)
432
- len = v.expressions.length - 1
433
- v.expressions.zip(v.columns).each_with_index { |(value, attr), i|
434
- case value
435
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
436
- collector = visit value, collector
437
- else
438
- collector << quote(value, attr && column_for(attr)).to_s
439
- end
440
- collector << Arel::Visitors::ToSql::COMMA unless i == len
431
+ len = row.length - 1
432
+ row.zip(o.cols).each_with_index { |(value, attr), i|
433
+ case value
434
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
435
+ collector = visit value, collector
436
+ else
437
+ collector << quote(value, attr && column_for(attr)).to_s
438
+ end
439
+ collector << Arel::Visitors::ToSql::COMMA unless i == len
441
440
  }
442
441
  collector << (idx == row_nb-1 ? ')' : '), ')
443
442
  end
@@ -449,16 +448,17 @@ module ArelExtensions
449
448
  row_nb = o.left.length
450
449
  o.left.each_with_index do |row, idx|
451
450
  collector << '('
452
- v = Arel::Nodes::Values.new(row, o.cols)
453
- len = v.expressions.length - 1
454
- v.expressions.zip(v.columns).each_with_index { |(value, attr), i|
455
- case value
456
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
457
- collector = visit value, collector
458
- else
459
- collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
460
- end
461
- collector << Arel::Visitors::ToSql::COMMA unless i == len
451
+ len = row.length - 1
452
+ row.zip(o.cols).each_with_index { |(value, attr), i|
453
+ case value
454
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
455
+ collector = visit value, collector
456
+ when Integer
457
+ collector << value.to_s
458
+ else
459
+ collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
460
+ end
461
+ collector << Arel::Visitors::ToSql::COMMA unless i == len
462
462
  }
463
463
  collector << (idx == row_nb-1 ? ')' : '), ')
464
464
  end
@@ -543,52 +543,45 @@ module ArelExtensions
543
543
  collector
544
544
  end
545
545
 
546
+ # Boolean logic.
547
+
546
548
  alias_method :old_visit_Arel_Nodes_And, :visit_Arel_Nodes_And
547
549
  def visit_Arel_Nodes_And o, collector
548
- collector << '('
549
550
  case o.children.length
550
551
  when 0
551
- collector << '1=1' # but this should not happen
552
+ collector << '1 = 1' # but this should not happen
552
553
  when 1
553
554
  collector = visit o.children[0], collector
554
555
  else
556
+ collector << '('
555
557
  o.children.each_with_index { |arg, i|
556
558
  if i != 0
557
559
  collector << ') AND ('
558
560
  end
559
561
  collector = visit arg, collector
560
562
  }
563
+ collector << ')'
561
564
  end
562
- collector << ')'
563
565
  collector
564
566
  end
565
567
 
566
- def visit_ArelExtensions_Nodes_Or o, collector
567
- collector << '('
568
+ alias_method :old_visit_Arel_Nodes_Or, :visit_Arel_Nodes_Or
569
+ def visit_Arel_Nodes_Or o, collector
568
570
  case o.children.length
569
571
  when 0
570
- collector << '0=1' # but this should not happen
572
+ collector << '1 = 0' # but this should not happen
571
573
  when 1
572
574
  collector = visit o.children[0], collector
573
575
  else
576
+ collector << '('
574
577
  o.children.each_with_index { |arg, i|
575
578
  if i != 0
576
579
  collector << ') OR ('
577
580
  end
578
581
  collector = visit arg, collector
579
582
  }
583
+ collector << ')'
580
584
  end
581
- collector << ')'
582
- collector
583
- end
584
-
585
- alias_method :old_visit_Arel_Nodes_Or, :visit_Arel_Nodes_Or
586
- def visit_Arel_Nodes_Or o, collector
587
- collector << '('
588
- collector = visit o.left, collector
589
- collector << ') OR ('
590
- collector = visit o.right, collector
591
- collector << ')'
592
585
  collector
593
586
  end
594
587
 
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'minitest/autorun'
3
+ require 'fileutils'
4
+ require 'arel'
5
+ require 'active_record'
6
+
7
+ require 'support/fake_record'
8
+
9
+ require 'arel_extensions'
10
+ Arel::Table.engine = FakeRecord::Base.new
11
+
12
+ $arel_silence_type_casting_deprecation = true
13
+
14
+ module Minitest::Assertions
15
+ #
16
+ # Fails unless +expected and +actual are the same string, modulo extraneous spaces.
17
+ #
18
+ def assert_like(expected, actual, msg = nil)
19
+ msg ||= "Expected #{expected.inspect} and #{actual.inspect} to be alike"
20
+ assert_equal expected.gsub(/\s+/, ' ').strip, actual.gsub(/\s+/, ' ').strip
21
+ end
22
+ end
23
+
24
+ module Minitest::Expectations
25
+
26
+ infect_an_assertion :assert_like, :must_be_like
27
+
28
+ end
@@ -65,6 +65,10 @@ module FakeRecord
65
65
  self
66
66
  end
67
67
 
68
+ def in_clause_length
69
+ 10000
70
+ end
71
+
68
72
  def quote thing, column = nil
69
73
  if column && !thing.nil?
70
74
  case column.type
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
 
3
3
  module ArelExtensions
4
4
  module Nodes
@@ -20,26 +20,27 @@ module ArelExtensions
20
20
  end
21
21
 
22
22
  it "< is equal lt" do
23
- compile(@table[:id] < 10).must_be_like('"users"."id" < 10')
23
+ _(compile(@table[:id] < 10)).must_be_like('"users"."id" < 10')
24
24
  end
25
25
 
26
26
  it "<= is equal lteq" do
27
- compile(@table[:id] <= 10).must_be_like('"users"."id" <= 10')
27
+ _(compile(@table[:id] <= 10)).must_be_like('"users"."id" <= 10')
28
28
  end
29
29
 
30
30
  it "> is equal gt" do
31
- compile(@table[:id] > 10).must_be_like('"users"."id" > 10')
31
+ _(compile(@table[:id] > 10)).must_be_like('"users"."id" > 10')
32
32
  end
33
33
 
34
34
  it "< is equal gteq" do
35
- compile(@table[:id] >= 10).must_be_like('"users"."id" >= 10')
35
+ _(compile(@table[:id] >= 10)).must_be_like('"users"."id" >= 10')
36
36
  end
37
37
 
38
38
  it "should compare with dates" do
39
- compile(@table[:created_at] >= Date.new(2016, 3, 31)).must_be_like %{"users"."created_at" >= '2016-03-31'}
39
+ _(compile(@table[:created_at] >= Date.new(2016, 3, 31)))
40
+ .must_be_like %{"users"."created_at" >= '2016-03-31'}
40
41
  end
41
42
 
42
43
  end
43
44
 
44
45
  end
45
- end
46
+ end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
 
3
3
  module ArelExtensions
4
4
  module BulkInsertOracle
@@ -25,8 +25,9 @@ module ArelExtensions
25
25
  it "should import large set of data in Oracle" do
26
26
  insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
27
27
  insert_manager.bulk_insert(@cols, @data)
28
- sql = compile(insert_manager.ast)
29
- sql.must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at") ((SELECT 'nom1', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL) UNION ALL (SELECT 'nom2', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL))]
28
+ _(compile(insert_manager.ast))
29
+ .must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at")
30
+ ((SELECT 'nom1', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL) UNION ALL (SELECT 'nom2', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL))]
30
31
  end
31
32
 
32
33
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
 
3
3
  module ArelExtensions
4
4
  module BulkInsertSQLlite
@@ -27,8 +27,9 @@ module ArelExtensions
27
27
  it "should import large set of data" do
28
28
  insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
29
29
  insert_manager.bulk_insert(@cols, @data)
30
- sql = compile(insert_manager.ast)
31
- sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") SELECT 23 AS 'id', 'nom1' AS 'name', 'sdfdsfdsfsdf' AS 'comments', '2016-01-01' AS 'created_at' UNION ALL SELECT 25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
30
+ _(compile(insert_manager.ast))
31
+ .must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at")
32
+ SELECT 23 AS 'id', 'nom1' AS 'name', 'sdfdsfdsfsdf' AS 'comments', '2016-01-01' AS 'created_at' UNION ALL SELECT 25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
32
33
  end
33
34
 
34
35
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
 
3
3
  module ArelExtensions
4
4
  module BulkInsertToSql
@@ -27,8 +27,8 @@ module ArelExtensions
27
27
  it "should import large set of data using ToSql" do
28
28
  insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
29
29
  insert_manager.bulk_insert(@cols, @data)
30
- sql = compile(insert_manager.ast)
31
- sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") VALUES (23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01'), (25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01')]
30
+ _(compile(insert_manager.ast))
31
+ .must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") VALUES (23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01'), (25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01')]
32
32
  end
33
33
  end
34
34
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
 
3
3
  module ArelExtensions
4
4
  module VisitorOracle
@@ -23,86 +23,86 @@ module ArelExtensions
23
23
  # Comparators
24
24
 
25
25
  it "should accept comparators on integers" do
26
- compile(@table[:id] == 42).must_match %{"users"."id" = 42}
27
- compile(@table[:id] == @table[:id]).must_be_like %{"users"."id" = "users"."id"}
28
- compile(@table[:id] != 42).must_match %{"users"."id" != 42}
29
- compile(@table[:id] > 42).must_match %{"users"."id" > 42}
30
- compile(@table[:id] >= 42).must_match %{"users"."id" >= 42}
31
- compile(@table[:id] >= @table[:id]).must_be_like %{"users"."id" >= "users"."id"}
32
- compile(@table[:id] < 42).must_match %{"users"."id" < 42}
33
- compile(@table[:id] <= 42).must_match %{"users"."id" <= 42}
34
- compile((@table[:id] <= 42).as('new_name')).must_match %{("users"."id" <= 42) AS new_name}
26
+ _(compile(@table[:id] == 42)).must_match %{"users"."id" = 42}
27
+ _(compile(@table[:id] == @table[:id])).must_be_like %{"users"."id" = "users"."id"}
28
+ _(compile(@table[:id] != 42)).must_match %{"users"."id" != 42}
29
+ _(compile(@table[:id] > 42)).must_match %{"users"."id" > 42}
30
+ _(compile(@table[:id] >= 42)).must_match %{"users"."id" >= 42}
31
+ _(compile(@table[:id] >= @table[:id])).must_be_like %{"users"."id" >= "users"."id"}
32
+ _(compile(@table[:id] < 42)).must_match %{"users"."id" < 42}
33
+ _(compile(@table[:id] <= 42)).must_match %{"users"."id" <= 42}
34
+ _(compile((@table[:id] <= 42).as('new_name'))).must_match %{("users"."id" <= 42) AS new_name}
35
35
  end
36
36
 
37
37
  it "should accept comparators on dates" do
38
38
  c = @table[:created_at]
39
39
  u = @table[:updated_at]
40
- compile(c > @date).must_be_like %{"users"."created_at" > '2016-03-31'}
41
- compile(u >= @date).must_be_like %{"users"."updated_at" >= '2016-03-31'}
42
- compile(c < u).must_be_like %{"users"."created_at" < "users"."updated_at"}
40
+ _(compile(c > @date)).must_be_like %{"users"."created_at" > '2016-03-31'}
41
+ _(compile(u >= @date)).must_be_like %{"users"."updated_at" >= '2016-03-31'}
42
+ _(compile(c < u)).must_be_like %{"users"."created_at" < "users"."updated_at"}
43
43
  end
44
44
 
45
45
  it "should accept comparators on strings" do
46
46
  c = @table[:name]
47
- compile(c == 'test').must_be_like %{"users"."name" = 'test'}
48
- compile(c != 'test').must_be_like %{"users"."name" != 'test'}
49
- compile(c > 'test').must_be_like %{"users"."name" > 'test'}
50
- compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
51
- compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
52
- compile(c =~ /\Atest\Z/).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
53
- compile(c =~ /\Atest\z/).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
54
- compile(c =~ '^test$').must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
55
- compile(c !~ /\Ate\Dst\Z/).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
56
- compile(c.imatches('%test%')).must_be_like %{LOWER("users"."name") LIKE LOWER('%test%')}
57
- compile(c.imatches_any(['%test%', 't2'])).must_be_like %{((LOWER("users"."name") LIKE LOWER('%test%')) OR (LOWER("users"."name") LIKE LOWER('t2')))}
58
- compile(c.idoes_not_match('%test%')).must_be_like %{LOWER("users"."name") NOT LIKE LOWER('%test%')}
47
+ _(compile(c == 'test')).must_be_like %{"users"."name" = 'test'}
48
+ _(compile(c != 'test')).must_be_like %{"users"."name" != 'test'}
49
+ _(compile(c > 'test')).must_be_like %{"users"."name" > 'test'}
50
+ _(compile((c >= 'test').as('new_name'))).must_be_like %{("users"."name" >= 'test') AS new_name}
51
+ _(compile(c <= @table[:comments])).must_be_like %{"users"."name" <= "users"."comments"}
52
+ _(compile(c =~ /\Atest\Z/)).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
53
+ _(compile(c =~ /\Atest\z/)).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
54
+ _(compile(c =~ '^test$')).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
55
+ _(compile(c !~ /\Ate\Dst\Z/)).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
56
+ _(compile(c.imatches('%test%'))).must_be_like %{LOWER("users"."name") LIKE LOWER('%test%')}
57
+ _(compile(c.imatches_any(['%test%', 't2']))).must_be_like %{((LOWER("users"."name") LIKE LOWER('%test%')) OR (LOWER("users"."name") LIKE LOWER('t2')))}
58
+ _(compile(c.idoes_not_match('%test%'))).must_be_like %{LOWER("users"."name") NOT LIKE LOWER('%test%')}
59
59
  end
60
60
 
61
61
  # Maths
62
62
  # DateDiff
63
63
  it "should diff date col and date" do
64
- compile(@table[:created_at] - Date.new(2016, 3, 31)).must_match %{"users"."created_at" - TO_DATE('2016-03-31')}
64
+ _(compile(@table[:created_at] - Date.new(2016, 3, 31))).must_match %{"users"."created_at" - TO_DATE('2016-03-31')}
65
65
  end
66
66
 
67
67
  it "should diff date col and datetime col" do
68
- compile(@table[:created_at] - @table[:updated_at]).must_match %{"users"."created_at" - "users"."updated_at"}
68
+ _(compile(@table[:created_at] - @table[:updated_at])).must_match %{"users"."created_at" - "users"."updated_at"}
69
69
  end
70
70
 
71
71
  it "should diff date col and datetime col with AS" do
72
72
  sql = compile((@table[:updated_at] - @table[:created_at]).as('new_name'))
73
73
  # sql.must_be_like %{(TO_DATE("users"."updated_at") - "users"."created_at") * 86400 AS new_name}
74
- sql.must_be_like %{("users"."updated_at" - "users"."created_at") * (CASE WHEN (TRUNC("users"."updated_at", 'DDD') = "users"."updated_at") THEN 1 ELSE 86400 END) AS new_name}
74
+ _(sql).must_be_like %{("users"."updated_at" - "users"."created_at") * (CASE WHEN (TRUNC("users"."updated_at", 'DDD') = "users"."updated_at") THEN 1 ELSE 86400 END) AS new_name}
75
75
  end
76
76
 
77
77
  it "should diff between time values" do
78
78
  d2 = Time.new(2015,6,1)
79
79
  d1 = DateTime.new(2015,6,2)
80
- sql = compile(ArelExtensions::Nodes::DateDiff.new([d1,d2]))
81
- sql.must_match("TO_DATE('2015-06-02') - TO_DATE('2015-06-01')")
80
+ _(compile(ArelExtensions::Nodes::DateDiff.new([d1,d2])))
81
+ .must_match("TO_DATE('2015-06-02') - TO_DATE('2015-06-01')")
82
82
  end
83
83
 
84
84
  it "should diff between time values and time col" do
85
85
  d1 = DateTime.new(2015,6,2)
86
- sql = compile(ArelExtensions::Nodes::DateDiff.new([d1, @table[:updated_at]]))
87
- sql.must_match %{TO_DATE('2015-06-02') - "users"."updated_at"}
86
+ _(compile(ArelExtensions::Nodes::DateDiff.new([d1, @table[:updated_at]])))
87
+ .must_match %{TO_DATE('2015-06-02') - "users"."updated_at"}
88
88
  end
89
89
 
90
90
  it "should accept operators on dates with numbers" do
91
91
  c = @table[:created_at]
92
- compile(c - 42).must_be_like %{DATE_SUB("users"."created_at", 42)}
93
- compile(c - @table[:id]).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
92
+ _(compile(c - 42)).must_be_like %{DATE_SUB("users"."created_at", 42)}
93
+ _(compile(c - @table[:id])).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
94
94
  end
95
95
 
96
96
  # Maths on sums
97
97
  it "should accept math operators on anything" do
98
98
  c = @table[:name]
99
- (c == 'test').to_sql.must_be_like %{"users"."name" = 'test'}
100
- (c != 'test').to_sql.must_be_like %{"users"."name" != 'test'}
101
- (c > 'test').to_sql.must_be_like %{"users"."name" > 'test'}
102
- compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
103
- compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
104
- compile(c =~ /\Atest\Z/).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
105
- compile(c !~ /\Ate\Dst\Z/).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
99
+ _((c == 'test').to_sql).must_be_like %{"users"."name" = 'test'}
100
+ _((c != 'test').to_sql).must_be_like %{"users"."name" != 'test'}
101
+ _((c > 'test').to_sql).must_be_like %{"users"."name" > 'test'}
102
+ _(compile((c >= 'test').as('new_name'))).must_be_like %{("users"."name" >= 'test') AS new_name}
103
+ _(compile(c <= @table[:comments])).must_be_like %{"users"."name" <= "users"."comments"}
104
+ _(compile(c =~ /\Atest\Z/)).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
105
+ _(compile(c !~ /\Ate\Dst\Z/)).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
106
106
  end
107
107
 
108
108
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
  require 'set'
3
3
 
4
4
  module ArelExtensions
@@ -22,379 +22,532 @@ module ArelExtensions
22
22
  end
23
23
  end
24
24
 
25
+ describe "primitive methods" do
26
+
27
+ it "should be able to recognize equal nodes" do
28
+ c = @table[:id]
29
+ _(c == 1).must_be :eql?, (c == 1)
30
+ _((c == 1).right.hash).must_equal (c == 1).right.hash
31
+ _((c == 1).hash).must_equal (c == 1).hash
32
+
33
+ _([c == 1, c == 1].uniq).must_equal [c == 1]
34
+ end
35
+
36
+ end
37
+
25
38
  # Math Functions
26
39
  it "should not break Arel functions" do
27
- compile(@price + 42).must_be_like %{("products"."price" + 42)}
28
- compile(@table[:id] + @table[:pas_en_base])
40
+ _(compile(@price + 42)).must_be_like %{("products"."price" + 42)}
41
+ _(compile(@table[:id] + @table[:pas_en_base]))
29
42
  .must_be_like %{("users"."id" + "users"."pas_en_base")}
30
- compile(@table[:pas_en_base] + @table[:id])
43
+ _(compile(@table[:pas_en_base] + @table[:id]))
31
44
  .must_be_like %{("users"."pas_en_base" + "users"."id")}
32
- compile(@table[:id] - @table[:pas_en_base])
45
+ _(compile(@table[:id] - @table[:pas_en_base]))
33
46
  .must_be_like %{("users"."id" - "users"."pas_en_base")}
34
- compile(@table[:pas_en_base] - @table[:id])
47
+ _(compile(@table[:pas_en_base] - @table[:id]))
35
48
  .must_be_like %{("users"."pas_en_base" - "users"."id")}
36
- compile(@table[:id] * @table[:pas_en_base])
49
+ _(compile(@table[:id] * @table[:pas_en_base]))
37
50
  .must_be_like %{"users"."id" * "users"."pas_en_base"}
38
- compile(@table[:pas_en_base] * @table[:id])
51
+ _(compile(@table[:pas_en_base] * @table[:id]))
39
52
  .must_be_like %{"users"."pas_en_base" * "users"."id"}
40
53
  end
41
54
 
42
55
  it "should return right calculations on numbers" do
43
56
  #puts (@price.abs + 42).inspect
44
- compile(@price.abs + 42).must_be_like %{(ABS("products"."price") + 42)}
45
- compile(@price.ceil + 42).must_be_like %{(CEIL("products"."price") + 42)}
46
- compile(@price.floor + 42).must_be_like %{(FLOOR("products"."price") + 42)}
47
- compile(@price.log10 + 42).must_be_like %{(LOG10("products"."price") + 42)}
48
- compile(@price.power(42) + 42).must_be_like %{(POW("products"."price", 42) + 42)}
49
- compile(@price.pow(42) + 42).must_be_like %{(POW("products"."price", 42) + 42)}
50
- compile(@price.ceil + @price.floor).must_be_like %{(CEIL("products"."price") + FLOOR("products"."price"))}
51
- compile((@price.ceil + @price.floor).abs).must_be_like %{ABS((CEIL("products"."price") + FLOOR("products"."price")))}
52
- compile(@price.round + 42).must_be_like %{(ROUND("products"."price") + 42)}
53
- compile(@price.round(2) + 42).must_be_like %{(ROUND("products"."price", 2) + 42)}
54
- compile(Arel.rand + 42).must_be_like %{(RAND() + 42)}
55
- compile(@price.sum + 42).must_be_like %{(SUM("products"."price") + 42)}
56
- compile((@price + 42).sum).must_be_like %{SUM(("products"."price" + 42))}
57
- compile((@price + 42).average).must_be_like %{AVG(("products"."price" + 42))}
58
- compile((Arel.rand * 9).round + 42).must_be_like %{(ROUND(RAND() * 9) + 42)}
59
- compile((Arel.rand * @price).round(2) + @price).must_be_like %{(ROUND(RAND() * "products"."price", 2) + "products"."price")}
60
-
61
- compile(@price.std + 42).must_be_like %{(STD("products"."price") + 42)}
62
- compile(@price.variance + 42).must_be_like %{(VARIANCE("products"."price") + 42)}
63
-
64
- compile(@price.coalesce(0) - 42).must_be_like %{(COALESCE("products"."price", 0) - 42)}
65
- compile(@price.sum - 42).must_be_like %{(SUM("products"."price") - 42)}
66
- compile(@price.std - 42).must_be_like %{(STD("products"."price") - 42)}
67
- compile(@price.variance - 42).must_be_like %{(VARIANCE("products"."price") - 42)}
68
-
69
- compile(@price * 42.0).must_be_like %{"products"."price" * 42.0}
70
- compile(@price / 42.0).must_be_like %{"products"."price" / 42.0}
57
+ _(compile(@price.abs + 42)).must_be_like %{(ABS("products"."price") + 42)}
58
+ _(compile(@price.ceil + 42)).must_be_like %{(CEIL("products"."price") + 42)}
59
+ _(compile(@price.floor + 42)).must_be_like %{(FLOOR("products"."price") + 42)}
60
+ _(compile(@price.log10 + 42)).must_be_like %{(LOG10("products"."price") + 42)}
61
+ _(compile(@price.power(42) + 42)).must_be_like %{(POW("products"."price", 42) + 42)}
62
+ _(compile(@price.pow(42) + 42)).must_be_like %{(POW("products"."price", 42) + 42)}
63
+ _(compile(@price.ceil + @price.floor)).must_be_like %{(CEIL("products"."price") + FLOOR("products"."price"))}
64
+ _(compile((@price.ceil + @price.floor).abs)).must_be_like %{ABS((CEIL("products"."price") + FLOOR("products"."price")))}
65
+ _(compile(@price.round + 42)).must_be_like %{(ROUND("products"."price") + 42)}
66
+ _(compile(@price.round(2) + 42)).must_be_like %{(ROUND("products"."price", 2) + 42)}
67
+ _(compile(Arel.rand + 42)).must_be_like %{(RAND() + 42)}
68
+ _(compile(@price.sum + 42)).must_be_like %{(SUM("products"."price") + 42)}
69
+ _(compile((@price + 42).sum)).must_be_like %{SUM(("products"."price" + 42))}
70
+ _(compile((@price + 42).average)).must_be_like %{AVG(("products"."price" + 42))}
71
+ _(compile((Arel.rand * 9).round + 42)).must_be_like %{(ROUND(RAND() * 9) + 42)}
72
+ _(compile((Arel.rand * @price).round(2) + @price)).must_be_like %{(ROUND(RAND() * "products"."price", 2) + "products"."price")}
73
+
74
+ _(compile(@price.std + 42)).must_be_like %{(STD("products"."price") + 42)}
75
+ _(compile(@price.variance + 42)).must_be_like %{(VARIANCE("products"."price") + 42)}
76
+
77
+ _(compile(@price.coalesce(0) - 42)).must_be_like %{(COALESCE("products"."price", 0) - 42)}
78
+ _(compile(@price.sum - 42)).must_be_like %{(SUM("products"."price") - 42)}
79
+ _(compile(@price.std - 42)).must_be_like %{(STD("products"."price") - 42)}
80
+ _(compile(@price.variance - 42)).must_be_like %{(VARIANCE("products"."price") - 42)}
81
+
82
+ _(compile(@price * 42.0)).must_be_like %{"products"."price" * 42.0}
83
+ _(compile(@price / 42.0)).must_be_like %{"products"."price" / 42.0}
71
84
 
72
85
  fake_table = Arel::Table.new('fake_tables')
73
86
 
74
- compile(fake_table[:fake_att] - 42).must_be_like %{("fake_tables"."fake_att" - 42)}
75
- compile(fake_table[:fake_att].coalesce(0) - 42).must_be_like %{(COALESCE("fake_tables"."fake_att", 0) - 42)}
87
+ _(compile(fake_table[:fake_att] - 42)).must_be_like %{("fake_tables"."fake_att" - 42)}
88
+ _(compile(fake_table[:fake_att].coalesce(0) - 42)).must_be_like %{(COALESCE("fake_tables"."fake_att", 0) - 42)}
76
89
  end
77
90
 
78
91
  # String Functions
79
92
  it "should accept functions on strings" do
80
93
  c = @table[:name]
81
- compile(c + 'test').must_be_like %{CONCAT(\"users\".\"name\", 'test')}
82
- compile(c.length).must_be_like %{LENGTH("users"."name")}
94
+ _(compile(c + 'test')).must_be_like %{CONCAT(\"users\".\"name\", 'test')}
95
+ _(compile(c.length)).must_be_like %{LENGTH("users"."name")}
83
96
  #puts (c.length.round + 42).inspect
84
- compile(c.length.round + 42).must_be_like %{(ROUND(LENGTH("users"."name")) + 42)}
85
- compile(c.locate('test')).must_be_like %{LOCATE('test', "users"."name")}
86
- compile(c & 42).must_be_like %{FIND_IN_SET(42, "users"."name")}
87
-
88
- compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
89
- compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
90
- compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
91
- compile(c =~ /\Atest\z/).must_be_like %{"users"."name" REGEXP '^test$'}
92
- compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
93
- compile(c.imatches('%test%')).must_be_like %{"users"."name" ILIKE '%test%'}
94
- compile(c.imatches_any(['%test%', 't2'])).must_be_like %{(("users"."name" ILIKE '%test%') OR ("users"."name" ILIKE 't2'))}
95
- compile(c.idoes_not_match('%test%')).must_be_like %{"users"."name" NOT ILIKE '%test%'}
96
-
97
- compile(c.substring(1)).must_be_like %{SUBSTRING("users"."name", 1)}
98
- compile(c + '0').must_be_like %{CONCAT("users"."name", '0')}
99
- compile(c.substring(1) + '0').must_be_like %{CONCAT(SUBSTRING("users"."name", 1), '0')}
100
- compile(c.substring(1) + c.substring(2)).must_be_like %{CONCAT(SUBSTRING("users"."name", 1), SUBSTRING("users"."name", 2))}
101
- compile(c.concat(c).concat(c)).must_be_like %{CONCAT("users"."name", "users"."name", "users"."name")}
102
- compile(c + c + c).must_be_like %{CONCAT("users"."name", "users"."name", "users"."name")}
97
+ _(compile(c.length.round + 42)).must_be_like %{(ROUND(LENGTH("users"."name")) + 42)}
98
+ _(compile(c.locate('test'))).must_be_like %{LOCATE('test', "users"."name")}
99
+ _(compile(c & 42)).must_be_like %{FIND_IN_SET(42, "users"."name")}
100
+
101
+ _(compile((c >= 'test').as('new_name'))).must_be_like %{("users"."name" >= 'test') AS new_name}
102
+ _(compile(c <= @table[:comments])).must_be_like %{"users"."name" <= "users"."comments"}
103
+ _(compile(c =~ /\Atest\Z/)).must_be_like %{"users"."name" REGEXP '^test$'}
104
+ _(compile(c =~ /\Atest\z/)).must_be_like %{"users"."name" REGEXP '^test$'}
105
+ _(compile(c !~ /\Ate\Dst\Z/)).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
106
+ _(compile(c.imatches('%test%'))).must_be_like %{"users"."name" ILIKE '%test%'}
107
+ _(compile(c.imatches_any(['%test%', 't2']))).must_be_like %{(("users"."name" ILIKE '%test%') OR ("users"."name" ILIKE 't2'))}
108
+ _(compile(c.idoes_not_match('%test%'))).must_be_like %{"users"."name" NOT ILIKE '%test%'}
109
+
110
+ _(compile(c.substring(1))).must_be_like %{SUBSTRING("users"."name", 1)}
111
+ _(compile(c + '0')).must_be_like %{CONCAT("users"."name", '0')}
112
+ _(compile(c.substring(1) + '0')).must_be_like %{CONCAT(SUBSTRING("users"."name", 1), '0')}
113
+ _(compile(c.substring(1) + c.substring(2))).must_be_like %{CONCAT(SUBSTRING("users"."name", 1), SUBSTRING("users"."name", 2))}
114
+ _(compile(c.concat(c).concat(c))).must_be_like %{CONCAT("users"."name", "users"."name", "users"."name")}
115
+ _(compile(c + c + c)).must_be_like %{CONCAT("users"."name", "users"."name", "users"."name")}
103
116
 
104
117
  # some optimization on concat
105
- compile(c + 'test' + ' chain').must_be_like %{CONCAT(\"users\".\"name\", 'test chain')}
106
- compile(Arel::Nodes.build_quoted('test') + ' chain').must_be_like %{'test chain'}
107
- compile(c + '' + c).must_be_like %{CONCAT(\"users\".\"name\", \"users\".\"name\")}
118
+ _(compile(c + 'test' + ' chain')).must_be_like %{CONCAT(\"users\".\"name\", 'test chain')}
119
+ _(compile(Arel::Nodes.build_quoted('test') + ' chain')).must_be_like %{'test chain'}
120
+ _(compile(c + '' + c)).must_be_like %{CONCAT(\"users\".\"name\", \"users\".\"name\")}
108
121
 
109
- compile(c.md5).must_be_like %{MD5(\"users\".\"name\")}
122
+ _(compile(c.md5)).must_be_like %{MD5(\"users\".\"name\")}
110
123
  end
111
124
 
112
125
  # Comparators
113
126
 
114
127
  it "should accept comparators on integers" do
115
- compile(@table[:id] == 42).must_match %{"users"."id" = 42}
116
- compile(@table[:id] == @table[:id]).must_be_like %{"users"."id" = "users"."id"}
117
- compile(@table[:id] != 42).must_match %{"users"."id" != 42}
118
- compile(@table[:id] > 42).must_match %{"users"."id" > 42}
119
- compile(@table[:id] >= 42).must_match %{"users"."id" >= 42}
120
- compile(@table[:id] >= @table[:id]).must_be_like %{"users"."id" >= "users"."id"}
121
- compile(@table[:id] < 42).must_match %{"users"."id" < 42}
122
- compile(@table[:id] <= 42).must_match %{"users"."id" <= 42}
123
- compile((@table[:id] <= 42).as('new_name')).must_match %{("users"."id" <= 42) AS new_name}
124
- compile(@table[:id].count.eq 42).must_match %{COUNT("users"."id") = 42}
125
- #compile(@table[:id].count == 42).must_match %{COUNT("users"."id") = 42} # TODO
126
- #compile(@table[:id].count != 42).must_match %{COUNT("users"."id") != 42}
127
- #compile(@table[:id].count >= 42).must_match %{COUNT("users"."id") >= 42}
128
+ _(compile(@table[:id] == 42)).must_match %{"users"."id" = 42}
129
+ _(compile(@table[:id] == @table[:id])).must_be_like %{"users"."id" = "users"."id"}
130
+ _(compile(@table[:id] != 42)).must_match %{"users"."id" != 42}
131
+ _(compile(@table[:id] > 42)).must_match %{"users"."id" > 42}
132
+ _(compile(@table[:id] >= 42)).must_match %{"users"."id" >= 42}
133
+ _(compile(@table[:id] >= @table[:id])).must_be_like %{"users"."id" >= "users"."id"}
134
+ _(compile(@table[:id] < 42)).must_match %{"users"."id" < 42}
135
+ _(compile(@table[:id] <= 42)).must_match %{"users"."id" <= 42}
136
+ _(compile((@table[:id] <= 42).as('new_name'))).must_match %{("users"."id" <= 42) AS new_name}
137
+ _(compile(@table[:id].count.eq 42)).must_match %{COUNT("users"."id") = 42}
138
+ #_(compile(@table[:id].count == 42)).must_match %{COUNT("users"."id") = 42} # TODO
139
+ #_(compile(@table[:id].count != 42)).must_match %{COUNT("users"."id") != 42}
140
+ #_(compile(@table[:id].count >= 42)).must_match %{COUNT("users"."id") >= 42}
128
141
  end
129
142
 
130
143
  it "should accept comparators on dates" do
131
144
  c = @table[:created_at]
132
145
  u = @table[:updated_at]
133
- compile(c > @date).must_be_like %{"users"."created_at" > '2016-03-31'}
134
- compile(u >= @date).must_be_like %{"users"."updated_at" >= '2016-03-31'}
135
- compile(c < u).must_be_like %{"users"."created_at" < "users"."updated_at"}
146
+ _(compile(c > @date)).must_be_like %{"users"."created_at" > '2016-03-31'}
147
+ _(compile(u >= @date)).must_be_like %{"users"."updated_at" >= '2016-03-31'}
148
+ _(compile(c < u)).must_be_like %{"users"."created_at" < "users"."updated_at"}
136
149
  end
137
150
 
138
151
  it "should accept comparators on strings" do
139
152
  c = @table[:name]
140
- compile(c == 'test').must_be_like %{"users"."name" = 'test'}
141
- compile(c != 'test').must_be_like %{"users"."name" != 'test'}
142
- compile(c > 'test').must_be_like %{"users"."name" > 'test'}
143
- compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
144
- compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
145
- compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
146
- compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
147
- compile(c.imatches('%test%')).must_be_like %{"users"."name" ILIKE '%test%'}
148
- compile(c.imatches_any(['%test%', 't2'])).must_be_like %{(("users"."name" ILIKE '%test%') OR ("users"."name" ILIKE 't2'))}
149
- compile(c.idoes_not_match('%test%')).must_be_like %{"users"."name" NOT ILIKE '%test%'}
153
+ _(compile(c == 'test')).must_be_like %{"users"."name" = 'test'}
154
+ _(compile(c != 'test')).must_be_like %{"users"."name" != 'test'}
155
+ _(compile(c > 'test')).must_be_like %{"users"."name" > 'test'}
156
+ _(compile((c >= 'test').as('new_name'))).must_be_like %{("users"."name" >= 'test') AS new_name}
157
+ _(compile(c <= @table[:comments])).must_be_like %{"users"."name" <= "users"."comments"}
158
+ _(compile(c =~ /\Atest\Z/)).must_be_like %{"users"."name" REGEXP '^test$'}
159
+ _(compile(c !~ /\Ate\Dst\Z/)).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
160
+ _(compile(c.imatches('%test%'))).must_be_like %{"users"."name" ILIKE '%test%'}
161
+ _(compile(c.imatches_any(['%test%', 't2']))).must_be_like %{(("users"."name" ILIKE '%test%') OR ("users"."name" ILIKE 't2'))}
162
+ _(compile(c.idoes_not_match('%test%'))).must_be_like %{"users"."name" NOT ILIKE '%test%'}
150
163
  end
151
164
 
152
165
  # Maths
153
166
  # DateDiff
154
167
  it "should diff date col and date" do
155
- compile(@table[:created_at] - Date.new(2016, 3, 31)).must_match %{DATEDIFF("users"."created_at", '2016-03-31')}
168
+ _(compile(@table[:created_at] - Date.new(2016, 3, 31))).must_match %{DATEDIFF("users"."created_at", '2016-03-31')}
156
169
  end
157
170
 
158
171
  it "should diff date col and datetime col" do
159
- compile(@table[:created_at] - @table[:updated_at]).must_match %{DATEDIFF("users"."created_at", "users"."updated_at")}
172
+ _(compile(@table[:created_at] - @table[:updated_at])).must_match %{DATEDIFF("users"."created_at", "users"."updated_at")}
160
173
  end
161
174
 
162
175
  it "should diff date col and datetime col with AS" do
163
- sql = compile((@table[:updated_at] - @table[:created_at]).as('new_name'))
164
- sql.must_match %{TIMEDIFF("users"."updated_at", "users"."created_at") AS new_name}
176
+ _(compile((@table[:updated_at] - @table[:created_at]).as('new_name')))
177
+ .must_match %{TIMEDIFF("users"."updated_at", "users"."created_at") AS new_name}
165
178
  end
166
179
 
167
180
  it "should diff between time values" do
168
181
  d2 = Time.new(2015,6,1)
169
182
  d1 = DateTime.new(2015,6,2)
170
- sql = compile(ArelExtensions::Nodes::DateDiff.new([d1, d2]))
171
- sql.must_match("DATEDIFF('2015-06-02', '2015-06-01')")
183
+ _(compile(ArelExtensions::Nodes::DateDiff.new([d1, d2])))
184
+ .must_match("DATEDIFF('2015-06-02', '2015-06-01')")
172
185
  end
173
186
 
174
187
  it "should diff between time values and time col" do
175
188
  d1 = DateTime.new(2015,6,2)
176
- sql = compile(ArelExtensions::Nodes::DateDiff.new([d1, @table[:updated_at]]))
177
- sql.must_match %{DATEDIFF('2015-06-02', "users"."updated_at")}
189
+ _(compile(ArelExtensions::Nodes::DateDiff.new([d1, @table[:updated_at]])))
190
+ .must_match %{DATEDIFF('2015-06-02', "users"."updated_at")}
178
191
  end
179
192
 
180
193
  it "should diff between date col and duration" do
181
194
  d1 = 10
182
195
  d2 = -10
183
- compile(@table[:created_at] - d1).
184
- must_match %{DATE_SUB("users"."created_at", 10)}
185
- compile(@table[:created_at] - d2).
186
- must_match %{DATE_SUB("users"."created_at", -10)}
196
+ _(compile(@table[:created_at] - d1))
197
+ .must_match %{DATE_SUB("users"."created_at", 10)}
198
+ _(compile(@table[:created_at] - d2))
199
+ .must_match %{DATE_SUB("users"."created_at", -10)}
187
200
  end
188
201
 
189
202
  it "should accept operators on dates with numbers" do
190
203
  c = @table[:created_at]
191
204
  #u = @table[:updated_at]
192
- compile(c - 42).must_be_like %{DATE_SUB("users"."created_at", 42)}
193
- compile(c - @table[:id]).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
205
+ _(compile(c - 42)).must_be_like %{DATE_SUB("users"."created_at", 42)}
206
+ _(compile(c - @table[:id])).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
194
207
  end
195
208
 
196
209
  # Maths on sums
197
210
  it "should accept math operators on anything" do
198
211
  c = @table[:name]
199
- (c == 'test').to_sql.must_be_like %{"users"."name" = 'test'}
200
- (c != 'test').to_sql.must_be_like %{"users"."name" != 'test'}
201
- (c > 'test').to_sql.must_be_like %{"users"."name" > 'test'}
202
- compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
203
- compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
204
- compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
205
- compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
212
+ _((c == 'test').to_sql)
213
+ .must_be_like %{"users"."name" = 'test'}
214
+ _((c != 'test').to_sql)
215
+ .must_be_like %{"users"."name" != 'test'}
216
+ _((c > 'test').to_sql)
217
+ .must_be_like %{"users"."name" > 'test'}
218
+ _(compile((c >= 'test').as('new_name'))).must_be_like %{("users"."name" >= 'test') AS new_name}
219
+ _(compile(c <= @table[:comments])).must_be_like %{"users"."name" <= "users"."comments"}
220
+ _(compile(c =~ /\Atest\Z/)).must_be_like %{"users"."name" REGEXP '^test$'}
221
+ _(compile(c !~ /\Ate\Dst\Z/)).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
206
222
  end
207
223
 
208
224
  it "should manage complex formulas" do
209
225
  c = @table[:name]
210
- compile(
211
- (c.length / 42).round(2).floor > (@table[:updated_at] - Date.new(2000, 3, 31)).abs.ceil
212
- ).must_be_like %{FLOOR(ROUND(LENGTH("users"."name") / 42, 2)) > CEIL(ABS(TIMEDIFF("users"."updated_at", '2000-03-31 00:00:00 UTC')))}
226
+ _(compile(
227
+ (c.length / 42).round(2).floor > (@table[:updated_at] - Date.new(2000, 3, 31)).abs.ceil
228
+ ))
229
+ .must_be_like %{FLOOR(ROUND(LENGTH("users"."name") / 42, 2)) > CEIL(ABS(TIMEDIFF("users"."updated_at", '2000-03-31 00:00:00 UTC')))}
213
230
  end
214
231
 
215
232
  it "should accept aggregator like GROUP CONCAT" do
216
- @table.project(@table[:first_name].group_concat).group(@table[:last_name]).to_sql
233
+ _(@table.project(@table[:first_name].group_concat).group(@table[:last_name]).to_sql)
217
234
  .must_be_like %{SELECT GROUP_CONCAT("users"."first_name") FROM "users" GROUP BY "users"."last_name"}
218
- @table.project(@table[:first_name].group_concat('++')).group(@table[:last_name]).to_sql
235
+ _(@table.project(@table[:first_name].group_concat('++')).group(@table[:last_name]).to_sql)
219
236
  .must_be_like %{SELECT GROUP_CONCAT("users"."first_name", '++') FROM "users" GROUP BY "users"."last_name"}
220
237
  end
221
238
 
222
239
  # Unions
223
240
  it "should accept union operators on queries and union nodes" do
224
241
  c = @table.project(@table[:name])
225
- compile(c + c)
242
+ _(compile(c + c))
226
243
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")}
227
- (c + c).to_sql
244
+ _((c + c).to_sql)
228
245
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")}
229
- (c + (c + c)).to_sql
246
+ _((c + (c + c)).to_sql)
230
247
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")}
231
- ((c + c) + c).to_sql
248
+ _(((c + c) + c).to_sql)
232
249
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")}
233
- (c + c + c).to_sql
250
+ _((c + c + c).to_sql)
234
251
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")}
235
- (c + c).as('union_table').to_sql
252
+ _((c + c).as('union_table').to_sql)
236
253
  .must_be_like %{((SELECT "users"."name" FROM "users") UNION (SELECT "users"."name" FROM "users")) union_table}
237
254
  c = @table.project(@table[:name])
238
- compile(c.union_all(c))
255
+ _(compile(c.union_all(c)))
239
256
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")}
240
- (c.union_all(c)).to_sql
257
+ _((c.union_all(c)).to_sql)
241
258
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")}
242
- (c.union_all(c.union_all(c))).to_sql
259
+ _((c.union_all(c.union_all(c))).to_sql)
243
260
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")}
244
- ((c.union_all(c)).union_all(c)).to_sql
261
+ _(((c.union_all(c)).union_all(c)).to_sql)
245
262
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")}
246
- (c.union_all(c).union_all(c)).to_sql
263
+ _((c.union_all(c).union_all(c)).to_sql)
247
264
  .must_be_like %{(SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")}
248
- (c.union_all(c)).as('union_table').to_sql
265
+ _((c.union_all(c)).as('union_table').to_sql)
249
266
  .must_be_like %{((SELECT "users"."name" FROM "users") UNION ALL (SELECT "users"."name" FROM "users")) union_table}
250
267
  end
251
268
 
252
269
  # Case
253
270
  it "should accept case clause" do
254
- @table[:name].when("smith").then("cool").when("doe").then("fine").else("uncool").to_sql
271
+ _(@table[:name].when("smith").then("cool").when("doe").then("fine").else("uncool").to_sql)
255
272
  .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' WHEN 'doe' THEN 'fine' ELSE 'uncool' END}
256
- @table[:name].when("smith").then(1).when("doe").then(2).else(0).to_sql
273
+ _(@table[:name].when("smith").then(1).when("doe").then(2).else(0).to_sql)
257
274
  .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 1 WHEN 'doe' THEN 2 ELSE 0 END}
258
- ArelExtensions::Nodes::Case.new.when(@table[:name] == "smith").then(1).when(@table[:name] == "doe").then(2).else(0).to_sql
275
+ _(ArelExtensions::Nodes::Case.new.when(@table[:name] == "smith").then(1).when(@table[:name] == "doe").then(2).else(0).to_sql)
259
276
  .must_be_like %{CASE WHEN "users"."name" = 'smith' THEN 1 WHEN "users"."name" = 'doe' THEN 2 ELSE 0 END}
260
- ArelExtensions::Nodes::Case.new(@table[:name]).when("smith").then(1).when("doe").then(2).else(0).to_sql
277
+ _(ArelExtensions::Nodes::Case.new(@table[:name]).when("smith").then(1).when("doe").then(2).else(0).to_sql)
261
278
  .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 1 WHEN 'doe' THEN 2 ELSE 0 END}
262
- @table[:name].when("smith").then(1).when("doe").then(2).else(0).sum.to_sql
279
+ _(@table[:name].when("smith").then(1).when("doe").then(2).else(0).sum.to_sql)
263
280
  .must_be_like %{SUM(CASE "users"."name" WHEN 'smith' THEN 1 WHEN 'doe' THEN 2 ELSE 0 END)}
264
- @table[:name].when("smith").then("cool").else("uncool").matches('value',false).to_sql
281
+ _(@table[:name].when("smith").then("cool").else("uncool").matches('value',false).to_sql)
265
282
  .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END LIKE 'value'}
266
- @table[:name].when("smith").then("cool").else("uncool").imatches('value',false).to_sql
283
+ _(@table[:name].when("smith").then("cool").else("uncool").imatches('value',false).to_sql)
267
284
  .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END ILIKE 'value'}
268
285
  end
269
286
 
270
287
  it "should be possible to use as on anything" do
271
- compile(@table[:name].as('alias')).must_be_like %{"users"."name" AS alias}
272
- compile(@table[:name].concat(' test').as('alias')).must_be_like %{CONCAT("users"."name", ' test') AS alias}
273
- compile((@table[:name] + ' test').as('alias')).must_be_like %{CONCAT("users"."name", ' test') AS alias}
274
- compile((@table[:age] + 42).as('alias')).must_be_like %{("users"."age" + 42) AS alias}
275
- compile(@table[:name].coalesce('').as('alias')).must_be_like %{COALESCE("users"."name", '') AS alias}
276
- compile(Arel::Nodes.build_quoted('test').as('alias')).must_be_like %{'test' AS alias}
277
- compile(@table.project(@table[:name]).as('alias')).must_be_like %{(SELECT "users"."name" FROM "users") alias}
278
- compile(@table[:name].when("smith").then("cool").else("uncool").as('alias')).
279
- must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END AS alias}
288
+ _(compile(@table[:name].as('alias'))).must_be_like %{"users"."name" AS alias}
289
+ _(compile(@table[:name].concat(' test').as('alias'))).must_be_like %{CONCAT("users"."name", ' test') AS alias}
290
+ _(compile((@table[:name] + ' test').as('alias'))).must_be_like %{CONCAT("users"."name", ' test') AS alias}
291
+ _(compile((@table[:age] + 42).as('alias'))).must_be_like %{("users"."age" + 42) AS alias}
292
+ _(compile(@table[:name].coalesce('').as('alias'))).must_be_like %{COALESCE("users"."name", '') AS alias}
293
+ _(compile(Arel::Nodes.build_quoted('test').as('alias'))).must_be_like %{'test' AS alias}
294
+ _(compile(@table.project(@table[:name]).as('alias'))).must_be_like %{(SELECT "users"."name" FROM "users") alias}
295
+ _(compile(@table[:name].when("smith").then("cool").else("uncool").as('alias')))
296
+ .must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END AS alias}
280
297
  end
281
298
 
282
299
  it "should accept comparators on functions" do
283
300
  c = @table[:name]
284
- compile(c.soundex == 'test').must_be_like %{SOUNDEX("users"."name") = 'test'}
285
- compile(c.soundex != 'test').must_be_like %{SOUNDEX("users"."name") != 'test'}
286
- compile(c.length >= 0 ).must_be_like %{LENGTH("users"."name") >= 0}
301
+ _(compile(c.soundex == 'test')).must_be_like %{SOUNDEX("users"."name") = 'test'}
302
+ _(compile(c.soundex != 'test')).must_be_like %{SOUNDEX("users"."name") != 'test'}
303
+ _(compile(c.length >= 0 )).must_be_like %{LENGTH("users"."name") >= 0}
287
304
  end
288
305
 
289
306
  it "should accept in on select statement" do
290
307
  c = @table[:name]
291
- compile(c.in(@table.project(@table[:name])))
308
+ _(compile(c.in(@table.project(@table[:name]))))
292
309
  .must_be_like %{"users"."name" IN (SELECT "users"."name" FROM "users")}
293
310
  end
294
311
 
295
312
  it "should accept coalesce function properly even on none actual tables and attributes" do
296
313
  fake_at = Arel::Table.new('fake_table')
297
- compile(fake_at['fake_attribute'].coalesce('other_value'))
314
+ _(compile(fake_at['fake_attribute'].coalesce('other_value')))
298
315
  .must_be_like %{COALESCE("fake_table"."fake_attribute", 'other_value')}
299
- compile(fake_at['fake_attribute'].coalesce('other_value1','other_value2'))
316
+ _(compile(fake_at['fake_attribute'].coalesce('other_value1','other_value2')))
300
317
  .must_be_like %{COALESCE("fake_table"."fake_attribute", 'other_value1', 'other_value2')}
301
- compile(fake_at['fake_attribute'].coalesce('other_value1').coalesce('other_value2'))
318
+ _(compile(fake_at['fake_attribute'].coalesce('other_value1').coalesce('other_value2')))
302
319
  .must_be_like %{COALESCE(COALESCE("fake_table"."fake_attribute", 'other_value1'), 'other_value2')}
303
- compile(fake_at['fake_attribute'].coalesce('other_value').matches('truc'))
320
+ _(compile(fake_at['fake_attribute'].coalesce('other_value').matches('truc')))
304
321
  .must_be_like %{COALESCE("fake_table"."fake_attribute", 'other_value') LIKE 'truc'}
305
- compile(fake_at['fake_attribute'].coalesce('other_value').imatches('truc'))
322
+ _(compile(fake_at['fake_attribute'].coalesce('other_value').imatches('truc')))
306
323
  .must_be_like %{COALESCE("fake_table"."fake_attribute", 'other_value') ILIKE 'truc'}
307
324
  end
308
325
 
309
326
  it "should be possible to cast nodes types" do
310
- compile(@table[:id].cast('char'))
327
+ _(compile(@table[:id].cast('char')))
311
328
  .must_be_like %{CAST("users"."id" AS char)}
312
- compile(@table[:id].coalesce(' ').cast('char'))
329
+ _(compile(@table[:id].coalesce(' ').cast('char')))
313
330
  .must_be_like %{CAST(COALESCE("users"."id", ' ') AS char)}
314
- compile(@table[:id].coalesce(' ').cast(:string))
331
+ _(compile(@table[:id].coalesce(' ').cast(:string)))
315
332
  .must_be_like %{CAST(COALESCE("users"."id", ' ') AS char)}
316
- compile(@table[:id].cast(:string).coalesce(' '))
333
+ _(compile(@table[:id].cast(:string).coalesce(' ')))
317
334
  .must_be_like %{COALESCE(CAST(\"users\".\"id\" AS char), ' ')}
318
- compile(@table[:id].cast('char') + ' ')
335
+ _(compile(@table[:id].cast('char') + ' '))
319
336
  .must_be_like %{CONCAT(CAST("users"."id" AS char), ' ')}
320
- compile(@table[:id].cast('int') + 2)
337
+ _(compile(@table[:id].cast('int') + 2))
321
338
  .must_be_like %{(CAST("users"."id" AS int) + 2)}
322
339
  end
323
340
 
324
- it "should be possible to have nil element in the function NIL" do
325
- compile(@table[:id].in(nil))
326
- .must_be_like %{ISNULL("users"."id")}
327
- compile(@table[:id].in([nil]))
328
- .must_be_like %{ISNULL("users"."id")}
329
- compile(@table[:id].in([nil,1]))
330
- .must_be_like %{(ISNULL("users"."id")) OR ("users"."id" = 1)}
331
- compile(@table[:id].in([nil,1,2]))
332
- .must_be_like %{(ISNULL("users"."id")) OR ("users"."id" IN (1, 2))}
333
- compile(@table[:id].in(1))
334
- .must_be_like %{"users"."id" IN (1)}
335
- compile(@table[:id].in([1]))
336
- .must_be_like %{"users"."id" = 1}
337
- compile(@table[:id].in([1,2]))
338
- .must_be_like %{"users"."id" IN (1, 2)}
339
- compile(@table[:id].in([]))
340
- .must_be_like %{ISNULL("users"."id")}
341
- end
341
+ describe "the function in" do
342
+
343
+ it "should be possible to have nil element in the function IN" do
344
+ _(compile(@table[:id].in(nil)))
345
+ .must_be_like %{ISNULL("users"."id")}
346
+ _(compile(@table[:id].in([nil])))
347
+ .must_be_like %{ISNULL("users"."id")}
348
+ _(compile(@table[:id].in([nil,1])))
349
+ .must_be_like %{(ISNULL("users"."id")) OR ("users"."id" = 1)}
350
+ _(compile(@table[:id].in([nil,1,2])))
351
+ .must_be_like %{(ISNULL("users"."id")) OR ("users"."id" IN (1, 2))}
352
+ _(compile(@table[:id].in(1)))
353
+ .must_be_like %{"users"."id" IN (1)}
354
+ _(compile(@table[:id].in([1])))
355
+ .must_be_like %{"users"."id" = 1}
356
+ _(compile(@table[:id].in([1,2])))
357
+ .must_be_like %{"users"."id" IN (1, 2)}
358
+ _(compile(@table[:id].in([])))
359
+ .must_be_like %{1 = 0}
360
+ end
361
+
362
+ it "should be possible to correctly use a Range on an IN" do
363
+ _(compile(@table[:id].in(1..4)))
364
+ .must_be_like %{"users"."id" BETWEEN (1) AND (4)}
365
+ _(compile(@table[:created_at].in(Date.new(2016, 3, 31) .. Date.new(2017, 3, 31))))
366
+ .must_be_like %{"users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31')}
367
+ end
368
+
369
+ it "should be possible to use a list of values and ranges on an IN" do
370
+ _(compile(@table[:id].in [1..10, 20, 30, 40..50]))
371
+ .must_be_like %{("users"."id" IN (20, 30)) OR ("users"."id" BETWEEN (1) AND (10)) OR ("users"."id" BETWEEN (40) AND (50))}
372
+ _(compile(@table[:created_at].in(Date.new(2016, 1, 1), Date.new(2016, 2, 1)..Date.new(2016, 2, 28), Date.new(2016, 3, 31) .. Date.new(2017, 3, 31), Date.new(2018, 1, 1))))
373
+ .must_be_like %{ ("users"."created_at" IN ('2016-01-01', '2018-01-01'))
374
+ OR ("users"."created_at" BETWEEN ('2016-02-01') AND ('2016-02-28'))
375
+ OR ("users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31'))}
376
+ end
377
+
378
+ it "should respecting Grouping" do
379
+ g = ->(*v) { Arel::Nodes::Grouping.new(v) }
380
+ _(compile(g[@table[:id], @table[:age]].in [g[1, 42]]))
381
+ .must_be_like %{("users"."id", "users"."age") IN ((1, 42))}
382
+ _(compile(g[@table[:id], @table[:age]].in [g[1, 42], g[2, 51]]))
383
+ .must_be_like %{("users"."id", "users"."age") IN ((1, 42), (2, 51))}
384
+
385
+ _(compile(g[@table[:id], @table[:age]].in(g[1, 42], g[2, 51])))
386
+ .must_be_like %{("users"."id", "users"."age") IN ((1, 42), (2, 51))}
387
+ end
388
+
342
389
 
343
- it "should be possible to correctly use a Range on an IN" do
344
- compile(@table[:id].in(1..4))
345
- .must_be_like %{"users"."id" BETWEEN (1) AND (4)}
346
- compile(@table[:created_at].in(@date .. Date.new(2017, 3, 31))) # @date = Date.new(2016, 3, 31)
347
- .must_be_like %{"users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31')}
348
390
  end
349
391
 
350
- it "should be possible to use a list of values and ranges on an IN" do
351
- compile(@table[:id].in [1..10, 20, 30, 40..50])
352
- .must_be_like %{(("users"."id" IN (20, 30)) OR ("users"."id" BETWEEN (1) AND (10))) OR ("users"."id" BETWEEN (40) AND (50))}
353
- # compile(@table[:created_at].in(@date .. Date.new(2017, 3, 31))) # @date = Date.new(2016, 3, 31)
354
- # .must_be_like %{"users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31')}
392
+ describe "the function not_in" do
393
+
394
+ it "should be possible to have nil element in the function IN" do
395
+ _(compile(@table[:id].not_in nil))
396
+ .must_be_like %{NOT ISNULL("users"."id")}
397
+ _(compile(@table[:id].not_in [nil]))
398
+ .must_be_like %{NOT ISNULL("users"."id")}
399
+ _(compile(@table[:id].not_in [nil,1]))
400
+ .must_be_like %{(NOT ISNULL("users"."id")) AND ("users"."id" != 1)}
401
+ _(compile(@table[:id].not_in [nil,1,2]))
402
+ .must_be_like %{(NOT ISNULL("users"."id")) AND ("users"."id" NOT IN (1, 2))}
403
+ _(compile(@table[:id].not_in 1))
404
+ .must_be_like %{"users"."id" NOT IN (1)}
405
+ _(compile(@table[:id].not_in [1]))
406
+ .must_be_like %{"users"."id" != 1}
407
+ _(compile(@table[:id].not_in [1,2]))
408
+ .must_be_like %{"users"."id" NOT IN (1, 2)}
409
+ _(compile(@table[:id].not_in []))
410
+ .must_be_like %{1 = 1}
411
+ end
412
+
413
+ it "should be possible to correctly use a Range on an IN" do
414
+ # FIXME: Should use NOT BETWEEN
415
+ _(compile(@table[:id].not_in 1..4))
416
+ .must_be_like %{NOT ("users"."id" BETWEEN (1) AND (4))}
417
+ # FIXME: Should use NOT BETWEEN
418
+ _(compile(@table[:created_at].not_in Date.new(2016, 3, 31) .. Date.new(2017, 3, 31)))
419
+ .must_be_like %{NOT ("users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31'))}
420
+ end
421
+
422
+ it "should be possible to use a list of values and ranges on an IN" do
423
+ _(compile(@table[:id].not_in [1..10, 20, 30, 40..50]))
424
+ .must_be_like %{ ("users"."id" NOT IN (20, 30))
425
+ AND (NOT ("users"."id" BETWEEN (1) AND (10)))
426
+ AND (NOT ("users"."id" BETWEEN (40) AND (50)))}
427
+ _(compile(@table[:created_at].not_in Date.new(2016, 1, 1), Date.new(2016, 2, 1)..Date.new(2016, 2, 28), Date.new(2016, 3, 31) .. Date.new(2017, 3, 31), Date.new(2018, 1, 1)))
428
+ .must_be_like %{ ("users"."created_at" NOT IN ('2016-01-01', '2018-01-01'))
429
+ AND (NOT ("users"."created_at" BETWEEN ('2016-02-01') AND ('2016-02-28')))
430
+ AND (NOT ("users"."created_at" BETWEEN ('2016-03-31') AND ('2017-03-31')))}
431
+ end
432
+
355
433
  end
356
434
 
357
435
  it "should be possible to add and substract as much as we want" do
358
436
  c = @table[:name]
359
- compile(c.locate('test')+1)
437
+ _(compile(c.locate('test')+1))
360
438
  .must_be_like %{(LOCATE('test', "users"."name") + 1)}
361
- compile(c.locate('test')-1)
439
+ _(compile(c.locate('test')-1))
362
440
  .must_be_like %{(LOCATE('test', "users"."name") - 1)}
363
- compile(c.locate('test')+c.locate('test'))
441
+ _(compile(c.locate('test')+c.locate('test')))
364
442
  .must_be_like %{(LOCATE('test', "users"."name") + LOCATE('test', "users"."name"))}
365
- compile(c.locate('test')+1+c.locate('test')-1 + 1)
443
+ _(compile(c.locate('test')+1+c.locate('test')-1 + 1))
366
444
  .must_be_like %{((((LOCATE('test', "users"."name") + 1) + LOCATE('test', "users"."name")) - 1) + 1)}
367
445
  end
368
446
 
369
447
  it "should be possible to add and substract on some nodes" do
370
448
  c = @table[:name]
371
- compile(c.when(0,0).else(42) + 42).must_be_like %{(CASE "users"."name" WHEN 0 THEN 0 ELSE 42 END + 42)}
372
- compile(c.when(0,0).else(42) - 42).must_be_like %{(CASE "users"."name" WHEN 0 THEN 0 ELSE 42 END - 42)}
373
- compile(c.when(0,"0").else("42") + "42").must_be_like %{CONCAT(CASE "users"."name" WHEN 0 THEN '0' ELSE '42' END, '42')}
449
+ _(compile(c.when(0,0).else(42) + 42)).must_be_like %{(CASE "users"."name" WHEN 0 THEN 0 ELSE 42 END + 42)}
450
+ _(compile(c.when(0,0).else(42) - 42)).must_be_like %{(CASE "users"."name" WHEN 0 THEN 0 ELSE 42 END - 42)}
451
+ _(compile(c.when(0,"0").else("42") + "42")).must_be_like %{CONCAT(CASE "users"."name" WHEN 0 THEN '0' ELSE '42' END, '42')}
374
452
  end
375
453
 
376
454
  it "should be possible to desc and asc on functions" do
377
455
  c = @table[:name]
378
- compile(c.asc)
456
+ _(compile(c.asc))
379
457
  .must_be_like %{"users"."name" ASC}
380
- compile(c.substring(2).asc)
458
+ _(compile(c.substring(2).asc))
381
459
  .must_be_like %{SUBSTRING("users"."name", 2) ASC}
382
- compile(c.substring(2).desc)
460
+ _(compile(c.substring(2).desc))
383
461
  .must_be_like %{SUBSTRING("users"."name", 2) DESC}
384
- compile((c.locate('test')+1).asc)
462
+ _(compile((c.locate('test')+1).asc))
385
463
  .must_be_like %{(LOCATE('test', "users"."name") + 1) ASC}
386
464
  end
387
465
 
388
- it "should be possible to have multiple arguments on an OR or an AND node" do
389
- c = @table[:id]
390
- compile((c == 1).and(c == 2, c == 3)).
391
- must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
392
- compile((c == 1).and([c == 2, c == 3])).
393
- must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
394
- compile((c == 1).or(c == 2, c == 3)).
395
- must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
396
- compile((c == 1).or([c == 2, c == 3])).
397
- must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
466
+ describe "logical functions" do
467
+
468
+ it "should know about truth" do
469
+ _(compile(Arel.false))
470
+ .must_be_like %{1 = 0}
471
+
472
+ _(compile(Arel::true))
473
+ .must_be_like %{1 = 1}
474
+ end
475
+
476
+ it "boolean nodes should be variadic" do
477
+ c = @table[:id]
478
+
479
+ _(compile(Arel::Nodes::And.new))
480
+ .must_be_like %{1 = 1}
481
+ _(compile(Arel::Nodes::And.new(c == 1)))
482
+ .must_be_like %{"users"."id" = 1}
483
+ _(compile(Arel::Nodes::And.new(c == 1, c == 2)))
484
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2)}
485
+ _(compile(Arel::Nodes::And.new [c == 1, c == 2, c == 3]))
486
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
487
+
488
+
489
+ _(compile(Arel::Nodes::Or.new))
490
+ .must_be_like %{1 = 0}
491
+ _(compile(Arel::Nodes::Or.new(c == 1)))
492
+ .must_be_like %{"users"."id" = 1}
493
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 2)))
494
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2)}
495
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 2, c == 3)))
496
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
497
+ _(compile(Arel::Nodes::Or.new [c == 1, c == 2, c == 3]))
498
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
499
+ end
500
+
501
+ it "should know trivial identities" do
502
+ skip "For future optimization"
503
+ c = @table[:id]
504
+ _(compile(Arel::Nodes::And.new(Arel.true, c == 1)))
505
+ .must_be_like %{"users"."id" = 1}
506
+ _(compile(Arel::Nodes::And.new(Arel.false, c == 1)))
507
+ .must_be_like %{1 = 0}
508
+ _(compile(Arel::Nodes::And.new(c == 1, c == 1)))
509
+ .must_be_like %{"users"."id" = 1}
510
+
511
+ _(compile(Arel::Nodes::Or.new(Arel.true, c == 1)))
512
+ .must_be_like %{1 = 1}
513
+ _(compile(Arel::Nodes::Or.new(Arel.false, c == 1)))
514
+ .must_be_like %{"users"."id" = 1}
515
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 1)))
516
+ .must_be_like %{"users"."id" = 1}
517
+ end
518
+
519
+ it "should be possible to have multiple arguments on an OR or an AND node" do
520
+ c = @table[:id]
521
+ _(compile((c == 1).and))
522
+ .must_be_like %{"users"."id" = 1}
523
+
524
+ _(compile((c == 1).and(c == 2, c == 3)))
525
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
526
+ _(compile((c == 1).and([c == 2, c == 3])))
527
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
528
+
529
+ _(compile((c == 1).or))
530
+ .must_be_like %{"users"."id" = 1}
531
+
532
+ _(compile((c == 1).or(c == 2, c == 3)))
533
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
534
+ _(compile((c == 1).or([c == 2, c == 3])))
535
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
536
+ end
537
+
538
+ it "should avoid useless nesting" do
539
+ c = @table[:id]
540
+ _(compile(((c == 1).and(c == 2)) .and ((c == 3).and(c == 4))))
541
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3) AND ("users"."id" = 4)}
542
+ _(compile(((c == 1).or(c == 2)) .or ((c == 3).or(c == 4))))
543
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3) OR ("users"."id" = 4)}
544
+
545
+ _(compile(((c == 1).or(c == 2)) .and ((c == 3).or(c == 4))))
546
+ .must_be_like %{(("users"."id" = 1) OR ("users"."id" = 2)) AND (("users"."id" = 3) OR ("users"."id" = 4))}
547
+ _(compile(((c == 1).and(c == 2)) .or ((c == 3).and(c == 4))))
548
+ .must_be_like %{(("users"."id" = 1) AND ("users"."id" = 2)) OR (("users"."id" = 3) AND ("users"."id" = 4))}
549
+ end
550
+
398
551
  end
399
552
 
400
553
  puts "AREL VERSION : " + Arel::VERSION.to_s