arel_extensions 2.0.4 → 2.0.8

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