arel_extensions 1.2.8 → 1.2.16

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/gemfiles/rails4.gemfile +1 -1
  6. data/gemfiles/rails6.gemfile +1 -1
  7. data/generate_gems.sh +4 -3
  8. data/lib/arel_extensions.rb +45 -20
  9. data/lib/arel_extensions/attributes.rb +0 -1
  10. data/lib/arel_extensions/boolean_functions.rb +39 -12
  11. data/lib/arel_extensions/insert_manager.rb +7 -5
  12. data/lib/arel_extensions/nodes/abs.rb +0 -0
  13. data/lib/arel_extensions/nodes/case.rb +8 -2
  14. data/lib/arel_extensions/nodes/ceil.rb +0 -0
  15. data/lib/arel_extensions/nodes/coalesce.rb +0 -0
  16. data/lib/arel_extensions/nodes/concat.rb +0 -0
  17. data/lib/arel_extensions/nodes/duration.rb +0 -0
  18. data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
  19. data/lib/arel_extensions/nodes/floor.rb +0 -0
  20. data/lib/arel_extensions/nodes/function.rb +0 -0
  21. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  22. data/lib/arel_extensions/nodes/json.rb +40 -25
  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 -17
  43. data/lib/arel_extensions/visitors/to_sql.rb +56 -55
  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 +366 -206
  52. data/test/with_ar/all_agnostic_test.rb +19 -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,4 +1,4 @@
1
- require 'helper'
1
+ require 'arelx_test_helper'
2
2
  require 'set'
3
3
 
4
4
  module ArelExtensions
@@ -22,379 +22,539 @@ 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
+ it "should be possible to call Table function on TableAlias" do
467
+ t = @table
468
+ a = t.alias("aliased_users")
469
+ _(compile(a.join(t).join_sources))
470
+ .must_be_like %{INNER JOIN \"users\"}
471
+ end
472
+
473
+ describe "logical functions" do
474
+
475
+ it "should know about truth" do
476
+ _(compile(Arel.false))
477
+ .must_be_like %{1 = 0}
478
+
479
+ _(compile(Arel::true))
480
+ .must_be_like %{1 = 1}
481
+ end
482
+
483
+ it "boolean nodes should be variadic" do
484
+ c = @table[:id]
485
+
486
+ _(compile(Arel::Nodes::And.new))
487
+ .must_be_like %{1 = 1}
488
+ _(compile(Arel::Nodes::And.new(c == 1)))
489
+ .must_be_like %{"users"."id" = 1}
490
+ _(compile(Arel::Nodes::And.new(c == 1, c == 2)))
491
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2)}
492
+ _(compile(Arel::Nodes::And.new [c == 1, c == 2, c == 3]))
493
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
494
+
495
+
496
+ _(compile(Arel::Nodes::Or.new))
497
+ .must_be_like %{1 = 0}
498
+ _(compile(Arel::Nodes::Or.new(c == 1)))
499
+ .must_be_like %{"users"."id" = 1}
500
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 2)))
501
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2)}
502
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 2, c == 3)))
503
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
504
+ _(compile(Arel::Nodes::Or.new [c == 1, c == 2, c == 3]))
505
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
506
+ end
507
+
508
+ it "should know trivial identities" do
509
+ skip "For future optimization"
510
+ c = @table[:id]
511
+ _(compile(Arel::Nodes::And.new(Arel.true, c == 1)))
512
+ .must_be_like %{"users"."id" = 1}
513
+ _(compile(Arel::Nodes::And.new(Arel.false, c == 1)))
514
+ .must_be_like %{1 = 0}
515
+ _(compile(Arel::Nodes::And.new(c == 1, c == 1)))
516
+ .must_be_like %{"users"."id" = 1}
517
+
518
+ _(compile(Arel::Nodes::Or.new(Arel.true, c == 1)))
519
+ .must_be_like %{1 = 1}
520
+ _(compile(Arel::Nodes::Or.new(Arel.false, c == 1)))
521
+ .must_be_like %{"users"."id" = 1}
522
+ _(compile(Arel::Nodes::Or.new(c == 1, c == 1)))
523
+ .must_be_like %{"users"."id" = 1}
524
+ end
525
+
526
+ it "should be possible to have multiple arguments on an OR or an AND node" do
527
+ c = @table[:id]
528
+ _(compile((c == 1).and))
529
+ .must_be_like %{"users"."id" = 1}
530
+
531
+ _(compile((c == 1).and(c == 2, c == 3)))
532
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
533
+ _(compile((c == 1).and([c == 2, c == 3])))
534
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3)}
535
+
536
+ _(compile((c == 1).or))
537
+ .must_be_like %{"users"."id" = 1}
538
+
539
+ _(compile((c == 1).or(c == 2, c == 3)))
540
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
541
+ _(compile((c == 1).or([c == 2, c == 3])))
542
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3)}
543
+ end
544
+
545
+ it "should avoid useless nesting" do
546
+ c = @table[:id]
547
+ _(compile(((c == 1).and(c == 2)) .and ((c == 3).and(c == 4))))
548
+ .must_be_like %{("users"."id" = 1) AND ("users"."id" = 2) AND ("users"."id" = 3) AND ("users"."id" = 4)}
549
+ _(compile(((c == 1).or(c == 2)) .or ((c == 3).or(c == 4))))
550
+ .must_be_like %{("users"."id" = 1) OR ("users"."id" = 2) OR ("users"."id" = 3) OR ("users"."id" = 4)}
551
+
552
+ _(compile(((c == 1).or(c == 2)) .and ((c == 3).or(c == 4))))
553
+ .must_be_like %{(("users"."id" = 1) OR ("users"."id" = 2)) AND (("users"."id" = 3) OR ("users"."id" = 4))}
554
+ _(compile(((c == 1).and(c == 2)) .or ((c == 3).and(c == 4))))
555
+ .must_be_like %{(("users"."id" = 1) AND ("users"."id" = 2)) OR (("users"."id" = 3) AND ("users"."id" = 4))}
556
+ end
557
+
398
558
  end
399
559
 
400
560
  puts "AREL VERSION : " + Arel::VERSION.to_s