arel_extensions 1.2.23 → 2.0.0.rc3

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -7
  3. data/.travis.yml +91 -61
  4. data/Gemfile +20 -15
  5. data/README.md +12 -17
  6. data/Rakefile +29 -40
  7. data/appveyor.yml +1 -1
  8. data/arel_extensions.gemspec +3 -3
  9. data/functions.html +3 -3
  10. data/gemfiles/rails3.gemfile +9 -9
  11. data/gemfiles/rails4.gemfile +13 -13
  12. data/gemfiles/rails5_0.gemfile +13 -13
  13. data/gemfiles/rails5_1_4.gemfile +13 -13
  14. data/gemfiles/rails5_2.gemfile +13 -13
  15. data/init/mssql.sql +4 -4
  16. data/init/mysql.sql +38 -38
  17. data/init/postgresql.sql +21 -21
  18. data/lib/arel_extensions.rb +19 -69
  19. data/lib/arel_extensions/attributes.rb +1 -0
  20. data/lib/arel_extensions/boolean_functions.rb +14 -55
  21. data/lib/arel_extensions/common_sql_functions.rb +8 -7
  22. data/lib/arel_extensions/comparators.rb +15 -14
  23. data/lib/arel_extensions/date_duration.rb +5 -4
  24. data/lib/arel_extensions/insert_manager.rb +16 -17
  25. data/lib/arel_extensions/math.rb +12 -11
  26. data/lib/arel_extensions/math_functions.rb +22 -29
  27. data/lib/arel_extensions/nodes.rb +1 -1
  28. data/lib/arel_extensions/nodes/abs.rb +1 -0
  29. data/lib/arel_extensions/nodes/blank.rb +1 -0
  30. data/lib/arel_extensions/nodes/case.rb +8 -11
  31. data/lib/arel_extensions/nodes/cast.rb +2 -4
  32. data/lib/arel_extensions/nodes/ceil.rb +1 -1
  33. data/lib/arel_extensions/nodes/change_case.rb +0 -0
  34. data/lib/arel_extensions/nodes/coalesce.rb +3 -2
  35. data/lib/arel_extensions/nodes/collate.rb +2 -1
  36. data/lib/arel_extensions/nodes/concat.rb +16 -7
  37. data/lib/arel_extensions/nodes/date_diff.rb +13 -10
  38. data/lib/arel_extensions/nodes/duration.rb +3 -0
  39. data/lib/arel_extensions/nodes/find_in_set.rb +1 -0
  40. data/lib/arel_extensions/nodes/floor.rb +1 -1
  41. data/lib/arel_extensions/nodes/format.rb +8 -34
  42. data/lib/arel_extensions/nodes/formatted_number.rb +23 -22
  43. data/lib/arel_extensions/nodes/function.rb +16 -25
  44. data/lib/arel_extensions/nodes/json.rb +36 -43
  45. data/lib/arel_extensions/nodes/length.rb +1 -0
  46. data/lib/arel_extensions/nodes/levenshtein_distance.rb +0 -0
  47. data/lib/arel_extensions/nodes/locate.rb +1 -0
  48. data/lib/arel_extensions/nodes/log10.rb +2 -1
  49. data/lib/arel_extensions/nodes/matches.rb +6 -4
  50. data/lib/arel_extensions/nodes/md5.rb +1 -0
  51. data/lib/arel_extensions/nodes/power.rb +5 -5
  52. data/lib/arel_extensions/nodes/rand.rb +1 -0
  53. data/lib/arel_extensions/nodes/repeat.rb +4 -2
  54. data/lib/arel_extensions/nodes/replace.rb +6 -22
  55. data/lib/arel_extensions/nodes/round.rb +6 -5
  56. data/lib/arel_extensions/nodes/soundex.rb +15 -15
  57. data/lib/arel_extensions/nodes/std.rb +21 -18
  58. data/lib/arel_extensions/nodes/substring.rb +16 -8
  59. data/lib/arel_extensions/nodes/then.rb +0 -0
  60. data/lib/arel_extensions/nodes/trim.rb +5 -3
  61. data/lib/arel_extensions/nodes/union.rb +5 -2
  62. data/lib/arel_extensions/nodes/union_all.rb +3 -0
  63. data/lib/arel_extensions/nodes/wday.rb +4 -0
  64. data/lib/arel_extensions/null_functions.rb +7 -5
  65. data/lib/arel_extensions/predications.rb +34 -35
  66. data/lib/arel_extensions/railtie.rb +5 -5
  67. data/lib/arel_extensions/set_functions.rb +4 -2
  68. data/lib/arel_extensions/string_functions.rb +22 -43
  69. data/lib/arel_extensions/tasks.rb +5 -5
  70. data/lib/arel_extensions/version.rb +1 -1
  71. data/lib/arel_extensions/visitors.rb +60 -68
  72. data/lib/arel_extensions/visitors/ibm_db.rb +12 -5
  73. data/lib/arel_extensions/visitors/mssql.rb +57 -63
  74. data/lib/arel_extensions/visitors/mysql.rb +98 -149
  75. data/lib/arel_extensions/visitors/oracle.rb +68 -71
  76. data/lib/arel_extensions/visitors/oracle12.rb +15 -2
  77. data/lib/arel_extensions/visitors/postgresql.rb +63 -116
  78. data/lib/arel_extensions/visitors/sqlite.rb +70 -83
  79. data/lib/arel_extensions/visitors/to_sql.rb +109 -141
  80. data/test/database.yml +0 -2
  81. data/test/helper.rb +18 -0
  82. data/test/real_db_test.rb +43 -28
  83. data/test/support/fake_record.rb +2 -2
  84. data/test/test_comparators.rb +12 -9
  85. data/test/visitors/test_bulk_insert_oracle.rb +8 -8
  86. data/test/visitors/test_bulk_insert_sqlite.rb +10 -9
  87. data/test/visitors/test_bulk_insert_to_sql.rb +10 -8
  88. data/test/visitors/test_oracle.rb +42 -42
  89. data/test/visitors/test_to_sql.rb +196 -361
  90. data/test/with_ar/all_agnostic_test.rb +160 -195
  91. data/test/with_ar/insert_agnostic_test.rb +4 -3
  92. data/test/with_ar/test_bulk_sqlite.rb +9 -6
  93. data/test/with_ar/test_math_sqlite.rb +12 -8
  94. data/test/with_ar/test_string_mysql.rb +11 -5
  95. data/test/with_ar/test_string_sqlite.rb +12 -4
  96. metadata +11 -22
  97. data/.github/workflows/ruby.yml +0 -102
  98. data/gemfiles/rails6.gemfile +0 -30
  99. data/gemfiles/rails6_1.gemfile +0 -30
  100. data/gemspecs/arel_extensions-v1.gemspec +0 -28
  101. data/gemspecs/arel_extensions-v2.gemspec +0 -28
  102. data/generate_gems.sh +0 -15
  103. data/lib/arel_extensions/nodes/aggregate_function.rb +0 -13
  104. data/lib/arel_extensions/nodes/sum.rb +0 -7
  105. data/lib/arel_extensions/visitors/convert_format.rb +0 -37
  106. data/test/arelx_test_helper.rb +0 -26
  107. data/version_v1.rb +0 -3
  108. data/version_v2.rb +0 -3
@@ -1,6 +1,7 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- class Arel::Visitors::IBM_DB
3
+ Arel::Visitors::IBM_DB.class_eval do
4
+
4
5
  def visit_ArelExtensions_Nodes_Ceil o, collector
5
6
  collector << "CEILING("
6
7
  collector = visit o.expr, collector
@@ -11,13 +12,14 @@ module ArelExtensions
11
12
  def visit_ArelExtensions_Nodes_Trim o, collector
12
13
  collector << "LTRIM(RTRIM("
13
14
  o.expressions.each_with_index { |arg, i|
14
- collector << COMMA if i != 0
15
+ collector << Arel::Visitors::IBM_DB::COMMA unless i == 0
15
16
  collector = visit arg, collector
16
17
  }
17
18
  collector << "))"
18
19
  collector
19
20
  end
20
21
 
22
+
21
23
  def visit_ArelExtensions_Nodes_DateDiff o, collector
22
24
  collector << "DAY("
23
25
  collector = visit o.left, collector
@@ -31,8 +33,9 @@ module ArelExtensions
31
33
  collector
32
34
  end
33
35
 
36
+
34
37
  def visit_ArelExtensions_Nodes_Duration o, collector
35
- # visit left for period
38
+ #visit left for period
36
39
  if o.left == "d"
37
40
  collector << "DAY("
38
41
  elsif o.left == "m"
@@ -42,7 +45,7 @@ module ArelExtensions
42
45
  elsif o.left == "y"
43
46
  collector << "YEAR("
44
47
  end
45
- # visit right
48
+ #visit right
46
49
  if o.right.is_a?(Arel::Attributes::Attribute)
47
50
  collector = visit o.right, collector
48
51
  else
@@ -52,11 +55,12 @@ module ArelExtensions
52
55
  collector
53
56
  end
54
57
 
58
+
55
59
  def visit_ArelExtensions_Nodes_IsNull o, collector
56
60
  collector << "COALESCE("
57
61
  collector = visit o.left, collector
58
62
  collector << ","
59
- if (o.right.is_a?(Arel::Attributes::Attribute))
63
+ if(o.right.is_a?(Arel::Attributes::Attribute))
60
64
  collector = visit o.right, collector
61
65
  else
62
66
  collector << "'#{o.right}'"
@@ -64,6 +68,9 @@ module ArelExtensions
64
68
  collector << ")"
65
69
  collector
66
70
  end
71
+
72
+
73
+
67
74
  end
68
75
  end
69
76
  end
@@ -1,26 +1,13 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
3
  module MSSQL
4
-
5
- Arel::Visitors::MSSQL::DATE_MAPPING = {
6
- 'd' => 'day', 'm' => 'month', 'y' => 'year', 'wd' => 'weekday', 'w' => 'week', 'h' => 'hour', 'mn' => 'minute', 's' => 'second'
7
- }.freeze
8
-
4
+ Arel::Visitors::MSSQL::DATE_MAPPING = {'d' => 'day', 'm' => 'month', 'y' => 'year', 'wd' => 'weekday', 'w' => 'week', 'h' => 'hour', 'mn' => 'minute', 's' => 'second'}
9
5
  Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES = {
10
6
  '%Y' => 'YYYY', '%C' => '', '%y' => 'YY', '%m' => 'MM', '%B' => '', '%b' => '', '%^b' => '', # year, month
11
7
  '%d' => 'DD', '%e' => '', '%j' => '', '%w' => 'dw', '%A' => '', # day, weekday
12
8
  '%H' => 'hh', '%k' => '', '%I' => '', '%l' => '', '%P' => '', '%p' => '', # hours
13
9
  '%M' => 'mi', '%S' => 'ss', '%L' => 'ms', '%N' => 'ns', '%z' => 'tz'
14
- }.freeze
15
-
16
- Arel::Visitors::MSSQL::DATE_FORMAT_REGEX =
17
- Regexp.new(
18
- Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES
19
- .keys
20
- .map{|k| Regexp.escape(k)}
21
- .join('|')
22
- ).freeze
23
-
10
+ }
24
11
  # TODO; all others... http://www.sql-server-helper.com/tips/date-formats.aspx
25
12
  Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS = {
26
13
  'YYYY-MM-DD' => 120,
@@ -32,7 +19,7 @@ module ArelExtensions
32
19
  'DD-MM-YY' => 5,
33
20
  'DD.MM.YYYY' => 104,
34
21
  'YYYY-MM-DDTHH:MM:SS:MMM' => 126
35
- }.freeze
22
+ }
36
23
 
37
24
  # Math Functions
38
25
  def visit_ArelExtensions_Nodes_Ceil o, collector
@@ -45,7 +32,7 @@ module ArelExtensions
45
32
  def visit_ArelExtensions_Nodes_Log10 o, collector
46
33
  collector << "LOG10("
47
34
  o.expressions.each_with_index { |arg, i|
48
- collector << Arel::Visitors::ToSql::COMMA if i != 0
35
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
49
36
  collector = visit arg, collector
50
37
  }
51
38
  collector << ")"
@@ -55,7 +42,7 @@ module ArelExtensions
55
42
  def visit_ArelExtensions_Nodes_Power o, collector
56
43
  collector << "POWER("
57
44
  o.expressions.each_with_index { |arg, i|
58
- collector << Arel::Visitors::ToSql::COMMA if i != 0
45
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
59
46
  collector = visit arg, collector
60
47
  }
61
48
  collector << ")"
@@ -79,7 +66,7 @@ module ArelExtensions
79
66
  def visit_ArelExtensions_Nodes_Concat o, collector
80
67
  collector << "CONCAT("
81
68
  o.expressions.each_with_index { |arg, i|
82
- collector << Arel::Visitors::MSSQL::COMMA if i != 0
69
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
83
70
  collector = visit arg, collector
84
71
  }
85
72
  collector << ")"
@@ -89,7 +76,7 @@ module ArelExtensions
89
76
  def visit_ArelExtensions_Nodes_Repeat o, collector
90
77
  collector << "REPLICATE("
91
78
  o.expressions.each_with_index { |arg, i|
92
- collector << Arel::Visitors::ToSql::COMMA if i != 0
79
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
93
80
  collector = visit arg, collector
94
81
  }
95
82
  collector << ")"
@@ -99,12 +86,12 @@ module ArelExtensions
99
86
 
100
87
 
101
88
  def visit_ArelExtensions_Nodes_DateDiff o, collector
102
- case o.right_node_type
103
- when :ruby_date, :ruby_time, :date, :datetime, :time
104
- collector << case o.left_node_type
105
- when :ruby_time, :datetime, :time then 'DATEDIFF(second'
106
- else 'DATEDIFF(day'
107
- end
89
+ if o.right_node_type == :ruby_date || o.right_node_type == :ruby_time || o.right_node_type == :date || o.right_node_type == :datetime || o.right_node_type == :time
90
+ collector << if o.left_node_type == :ruby_time || o.left_node_type == :datetime || o.left_node_type == :time
91
+ 'DATEDIFF(second'
92
+ else
93
+ 'DATEDIFF(day'
94
+ end
108
95
  collector << Arel::Visitors::MSSQL::COMMA
109
96
  collector = visit o.right, collector
110
97
  collector << Arel::Visitors::MSSQL::COMMA
@@ -164,7 +151,7 @@ module ArelExtensions
164
151
  def visit_ArelExtensions_Nodes_Round o, collector
165
152
  collector << "ROUND("
166
153
  o.expressions.each_with_index { |arg, i|
167
- collector << Arel::Visitors::MSSQL::COMMA if i != 0
154
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
168
155
  collector = visit arg, collector
169
156
  }
170
157
  if o.expressions.length == 1
@@ -255,34 +242,42 @@ module ArelExtensions
255
242
  end
256
243
 
257
244
  def visit_ArelExtensions_Nodes_Format o, collector
258
- f = ArelExtensions::Visitors::strftime_to_format(o.iso_format, Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES)
259
- if fmt = Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS[f]
245
+ f = o.iso_format.dup
246
+ Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
247
+ if Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS[f]
260
248
  collector << "CONVERT(VARCHAR(#{f.length})"
261
249
  collector << Arel::Visitors::MSSQL::COMMA
262
250
  collector = visit o.left, collector
263
251
  collector << Arel::Visitors::MSSQL::COMMA
264
- collector << fmt.to_s
252
+ collector << Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS[f].to_s
265
253
  collector << ')'
266
254
  collector
267
255
  else
268
- s = StringScanner.new o.iso_format
269
256
  collector << "("
270
- sep = ''
271
- while !s.eos?
272
- collector << sep
273
- sep = ' + '
274
- case
275
- when s.scan(Arel::Visitors::MSSQL::DATE_FORMAT_REGEX)
276
- dir = Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES[s.matched]
277
- collector << 'LTRIM(STR(DATEPART('
278
- collector << dir
279
- collector << Arel::Visitors::MSSQL::COMMA
280
- collector = visit o.left, collector
281
- collector << ')))'
282
- when s.scan(/[^%]+|./)
283
- collector = visit Arel::Nodes.build_quoted(s.matched), collector
257
+ t = o.iso_format.split('%')
258
+ t.each_with_index {|str, i|
259
+ if i == 0 && t[0] != '%'
260
+ collector = visit Arel::Nodes.build_quoted(str), collector
261
+ if str.length > 1
262
+ collector << Arel::Visitors::MSSQL::COMMA
263
+ collector = visit Arel::Nodes.build_quoted(str.sub(/\A./, '')), collector
264
+ end
265
+ elsif str.length > 0
266
+ if !Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]].blank?
267
+ collector << 'LTRIM(STR(DATEPART('
268
+ collector << Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]]
269
+ collector << Arel::Visitors::MSSQL::COMMA
270
+ collector = visit o.left, collector
271
+ collector << ')))'
272
+ if str.length > 1
273
+ collector << ' + '
274
+ collector = visit Arel::Nodes.build_quoted(str.sub(/\A./, '')), collector
275
+ end
276
+ end
284
277
  end
285
- end
278
+ collector << ' + ' if t[i + 1]
279
+ }
280
+
286
281
  collector << ')'
287
282
  collector
288
283
  end
@@ -291,7 +286,7 @@ module ArelExtensions
291
286
  def visit_ArelExtensions_Nodes_Replace o, collector
292
287
  collector << "REPLACE("
293
288
  o.expressions.each_with_index { |arg, i|
294
- collector << Arel::Visitors::MSSQL::COMMA if i != 0
289
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
295
290
  collector = visit arg, collector
296
291
  }
297
292
  collector << ")"
@@ -301,7 +296,7 @@ module ArelExtensions
301
296
  def visit_ArelExtensions_Nodes_FindInSet o, collector
302
297
  collector << "dbo.FIND_IN_SET("
303
298
  o.expressions.each_with_index { |arg, i|
304
- collector << Arel::Visitors::MSSQL::COMMA if i != 0
299
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
305
300
  collector = visit arg, collector
306
301
  }
307
302
  collector << ")"
@@ -405,16 +400,15 @@ module ArelExtensions
405
400
  collector << "(STRING_AGG("
406
401
  collector = visit o.left, collector
407
402
  collector << Arel::Visitors::Oracle::COMMA
408
- collector =
409
- if o.separator && o.separator != 'NULL'
410
- visit o.separator, collector
411
- else
412
- visit Arel::Nodes.build_quoted(','), collector
413
- end
403
+ if o.right && o.right != 'NULL'
404
+ collector = visit o.right, collector
405
+ else
406
+ collector = visit Arel::Nodes.build_quoted(','), collector
407
+ end
414
408
  collector << ") WITHIN GROUP (ORDER BY "
415
- if o.order.present?
416
- o.order.each_with_index do |order,i|
417
- collector << Arel::Visitors::Oracle::COMMA if i != 0
409
+ if !o.orders.blank?
410
+ o.orders.each_with_index do |order,i|
411
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
418
412
  collector = visit order, collector
419
413
  end
420
414
  else
@@ -472,9 +466,8 @@ module ArelExtensions
472
466
  Arel::Nodes.build_quoted(1) :
473
467
  ArelExtensions::Nodes::Case.new.when(col<0).then(1).else(0)
474
468
 
475
- number =
476
- if o.scientific_notation
477
- ArelExtensions::Nodes::Concat.new([
469
+ if o.scientific_notation
470
+ number = ArelExtensions::Nodes::Concat.new([
478
471
  Arel::Nodes::NamedFunction.new('FORMAT',[
479
472
  col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
480
473
  param,
@@ -487,13 +480,13 @@ module ArelExtensions
487
480
  locale
488
481
  ])
489
482
  ])
490
- else
491
- Arel::Nodes::NamedFunction.new('FORMAT',[
483
+ else
484
+ number = Arel::Nodes::NamedFunction.new('FORMAT',[
492
485
  Arel::Nodes.build_quoted(col.abs),
493
486
  param,
494
487
  locale
495
488
  ])
496
- end
489
+ end
497
490
 
498
491
  repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
499
492
  when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
@@ -555,6 +548,7 @@ module ArelExtensions
555
548
  collector
556
549
  end
557
550
 
551
+
558
552
  end
559
553
  end
560
554
  end
@@ -1,24 +1,21 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- class Arel::Visitors::MySQL
4
- DATE_MAPPING = {
5
- 'd' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY',
6
- 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'
7
- }.freeze
8
-
9
- DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
3
+ Arel::Visitors::MySQL.class_eval do
4
+ Arel::Visitors::MySQL::COMMA = ", "
5
+ Arel::Visitors::MySQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
6
+ Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
10
7
  '%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
11
8
  '%d' => '%d', '%e' => '%e', '%j' => '%j', '%w' => '%w', '%A' => '%W', # day, weekday
12
9
  '%H' => '%H', '%k' => '%k', '%I' => '%I', '%l' => '%l', '%P' => '%p', '%p' => '%p', # hours
13
10
  '%M' => '%i', '%S' => '%S', '%L' => '', '%N' => '%f', '%z' => ''
14
- }.freeze
11
+ }
15
12
 
16
13
 
17
- # Math functions
14
+ #Math functions
18
15
  def visit_ArelExtensions_Nodes_Log10 o, collector
19
16
  collector << "LOG10("
20
17
  o.expressions.each_with_index { |arg, i|
21
- collector << Arel::Visitors::ToSql::COMMA if i != 0
18
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
22
19
  collector = visit arg, collector
23
20
  }
24
21
  collector << ")"
@@ -28,14 +25,14 @@ module ArelExtensions
28
25
  def visit_ArelExtensions_Nodes_Power o, collector
29
26
  collector << "POW("
30
27
  o.expressions.each_with_index { |arg, i|
31
- collector << Arel::Visitors::ToSql::COMMA if i != 0
28
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
32
29
  collector = visit arg, collector
33
30
  }
34
31
  collector << ")"
35
32
  collector
36
33
  end
37
34
 
38
- # String functions
35
+ #String functions
39
36
  def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
40
37
  collector << 'LOWER('
41
38
  collector = visit o.left, collector
@@ -101,35 +98,33 @@ module ArelExtensions
101
98
  end
102
99
 
103
100
  def visit_ArelExtensions_Nodes_Collate o, collector
104
- charset =
105
- case o.expressions.first
106
- when Arel::Attributes::Attribute
107
- case o.option
101
+ case o.expressions.first
102
+ when Arel::Attributes::Attribute
103
+ charset = case o.option
108
104
  when 'latin1','utf8'
109
105
  o.option
110
106
  else
111
107
  Arel::Table.engine.connection.charset || 'utf8'
112
108
  end
113
- else
114
- (o.option == 'latin1') ? 'latin1' : 'utf8'
115
- end
109
+ else
110
+ charset = (o.option == 'latin1') ? 'latin1' : 'utf8'
111
+ end
116
112
  collector = visit o.expressions.first, collector
117
- collector <<
118
- if o.ai
119
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
120
- # doesn't work in latin1
121
- elsif o.ci
122
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
123
- else
124
- " COLLATE #{charset}_bin"
125
- end
113
+ if o.ai
114
+ collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
115
+ #doesn't work in latin1
116
+ elsif o.ci
117
+ collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
118
+ else
119
+ collector << " COLLATE #{charset}_bin"
120
+ end
126
121
  collector
127
122
  end
128
123
 
129
124
  def visit_ArelExtensions_Nodes_Concat o, collector
130
125
  collector << "CONCAT("
131
126
  o.expressions.each_with_index { |arg, i|
132
- collector << COMMA if i != 0
127
+ collector << Arel::Visitors::MySQL::COMMA unless i == 0
133
128
  if (arg.is_a?(Numeric)) || (arg.is_a?(Arel::Attributes::Attribute))
134
129
  collector << "CAST("
135
130
  collector = visit arg, collector
@@ -145,16 +140,16 @@ module ArelExtensions
145
140
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
146
141
  collector << "GROUP_CONCAT("
147
142
  collector = visit o.left, collector
148
- if !o.order.blank?
143
+ if !o.orders.blank?
149
144
  collector << ' ORDER BY '
150
- o.order.each_with_index do |order,i|
151
- collector << Arel::Visitors::ToSql::COMMA if i != 0
145
+ o.orders.each_with_index do |order,i|
146
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
152
147
  collector = visit order, collector
153
148
  end
154
149
  end
155
- if o.separator && o.separator != 'NULL'
150
+ if o.right && o.right != 'NULL'
156
151
  collector << ' SEPARATOR '
157
- collector = visit o.separator, collector
152
+ collector = visit o.right, collector
158
153
  end
159
154
  collector << ")"
160
155
  collector
@@ -169,7 +164,7 @@ module ArelExtensions
169
164
  collector
170
165
  end
171
166
 
172
- def visit_ArelExtensions_Nodes_Ltrim o, collector
167
+ def visit_ArelExtensions_Nodes_Ltrim o , collector
173
168
  collector << 'TRIM(LEADING '
174
169
  collector = visit o.right, collector
175
170
  collector << " FROM "
@@ -178,7 +173,7 @@ module ArelExtensions
178
173
  collector
179
174
  end
180
175
 
181
- def visit_ArelExtensions_Nodes_Rtrim o, collector
176
+ def visit_ArelExtensions_Nodes_Rtrim o , collector
182
177
  collector << 'TRIM(TRAILING '
183
178
  collector = visit o.right, collector
184
179
  collector << " FROM "
@@ -190,28 +185,22 @@ module ArelExtensions
190
185
  def visit_ArelExtensions_Nodes_Repeat o, collector
191
186
  collector << "REPEAT("
192
187
  o.expressions.each_with_index { |arg, i|
193
- collector << Arel::Visitors::ToSql::COMMA if i != 0
188
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
194
189
  collector = visit arg, collector
195
190
  }
196
191
  collector << ")"
197
192
  collector
198
193
  end
199
194
 
200
- def visit_ArelExtensions_Nodes_RegexpReplace o, collector
201
- if !regexp_replace_supported?
202
- warn("Warning : ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash")
203
- end
204
- super(o,collector)
205
- end
206
-
207
195
  def visit_ArelExtensions_Nodes_Format o, collector
208
196
  case o.col_type
209
- when :date, :datetime, :time
210
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
197
+ when :date, :datetime
211
198
  collector << "DATE_FORMAT("
212
199
  collector = visit o.left, collector
213
- collector << COMMA
214
- collector = visit Arel::Nodes.build_quoted(fmt), collector
200
+ collector << Arel::Visitors::MySQL::COMMA
201
+ f = o.iso_format.dup
202
+ Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
203
+ collector = visit Arel::Nodes.build_quoted(f), collector
215
204
  collector << ")"
216
205
  when :integer, :float, :decimal
217
206
  collector << "FORMAT("
@@ -228,15 +217,14 @@ module ArelExtensions
228
217
  end
229
218
 
230
219
  def visit_ArelExtensions_Nodes_DateDiff o, collector
231
- case o.right_node_type
232
- when :ruby_date, :ruby_time, :date, :datetime, :time
233
- collector <<
234
- case o.left_node_type
235
- when :ruby_time, :datetime, :time then 'TIMESTAMPDIFF(SECOND, '
236
- else 'DATEDIFF('
237
- end
220
+ if o.right_node_type == :ruby_date || o.right_node_type == :ruby_time || o.right_node_type == :date || o.right_node_type == :datetime || o.right_node_type == :time
221
+ collector << if o.left_node_type == :ruby_time || o.left_node_type == :datetime || o.left_node_type == :time
222
+ 'TIMESTAMPDIFF(SECOND, '
223
+ else
224
+ 'DATEDIFF('
225
+ end
238
226
  collector = visit o.right, collector
239
- collector << COMMA
227
+ collector << Arel::Visitors::MySQL::COMMA
240
228
  collector = visit o.left, collector
241
229
  collector << ")"
242
230
  else
@@ -260,12 +248,13 @@ module ArelExtensions
260
248
  def visit_ArelExtensions_Nodes_DateAdd o, collector
261
249
  collector << "DATE_ADD("
262
250
  collector = visit o.left, collector
263
- collector << COMMA
251
+ collector << Arel::Visitors::MySQL::COMMA
264
252
  collector = visit o.mysql_value(o.right), collector
265
253
  collector << ")"
266
254
  collector
267
255
  end
268
256
 
257
+
269
258
  def visit_ArelExtensions_Nodes_Duration o, collector
270
259
  if o.left == 'wd'
271
260
  collector << "(WEEKDAY("
@@ -274,18 +263,18 @@ module ArelExtensions
274
263
  else
275
264
  if o.with_interval
276
265
  case o.left
277
- when 'd','m','y'
266
+ when 'd','m','y'
278
267
  interval = 'DAY'
279
268
  when 'h','mn','s'
280
269
  interval = 'SECOND'
281
270
  when /i\z/
282
- interval = DATE_MAPPING[o.left[0..-2]]
271
+ interval = Arel::Visitors::MySQL::DATE_MAPPING[o.left[0..-2]]
283
272
  else
284
273
  interval = nil
285
274
  end
286
275
  end
287
276
  collector << " INTERVAL " if o.with_interval && interval
288
- collector << "#{DATE_MAPPING[o.left]}("
277
+ collector << "#{Arel::Visitors::MySQL::DATE_MAPPING[o.left]}("
289
278
  collector = visit o.right, collector
290
279
  collector << ")"
291
280
  collector << " #{interval} " if o.with_interval && interval
@@ -293,6 +282,7 @@ module ArelExtensions
293
282
  collector
294
283
  end
295
284
 
285
+
296
286
  def visit_ArelExtensions_Nodes_IsNull o, collector
297
287
  collector << "ISNULL("
298
288
  collector = visit o.expr, collector
@@ -318,25 +308,30 @@ module ArelExtensions
318
308
  collector << "CAST("
319
309
  collector = visit o.left, collector
320
310
  collector << " AS "
321
- as_attr =
322
- Arel::Nodes::SqlLiteral.new(
323
- case o.as_attr
324
- when :string then 'char'
325
- when :time then 'time'
326
- when :int then 'signed'
327
- when :number, :decimal then 'decimal(20,6)'
328
- when :datetime then 'datetime'
329
- when :date then 'date'
330
- when :binary then 'binary'
331
- else o.as_attr.to_s
332
- end
333
- )
311
+ case o.as_attr
312
+ when :string
313
+ as_attr = Arel::Nodes::SqlLiteral.new('char')
314
+ when :time
315
+ as_attr = Arel::Nodes::SqlLiteral.new('time')
316
+ when :int
317
+ as_attr = Arel::Nodes::SqlLiteral.new('signed')
318
+ when :number, :decimal
319
+ as_attr = Arel::Nodes::SqlLiteral.new('decimal(20,6)')
320
+ when :datetime
321
+ as_attr = Arel::Nodes::SqlLiteral.new('datetime')
322
+ when :date
323
+ as_attr = Arel::Nodes::SqlLiteral.new('date')
324
+ when :binary
325
+ as_attr = Arel::Nodes::SqlLiteral.new('binary')
326
+ else
327
+ as_attr = Arel::Nodes::SqlLiteral.new(o.as_attr.to_s)
328
+ end
334
329
  collector = visit as_attr, collector
335
330
  collector << ")"
336
331
  collector
337
332
  end
338
333
 
339
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
334
+ alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
340
335
  def visit_Arel_Nodes_SelectStatement o, collector
341
336
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
342
337
  o = o.dup
@@ -345,7 +340,7 @@ module ArelExtensions
345
340
  old_visit_Arel_Nodes_SelectStatement(o,collector)
346
341
  end
347
342
 
348
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
343
+ alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
349
344
  def visit_Arel_Nodes_As o, collector
350
345
  if o.left.is_a?(Arel::Nodes::Binary)
351
346
  collector << '('
@@ -368,21 +363,20 @@ module ArelExtensions
368
363
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
369
364
  sign_length = ArelExtensions::Nodes::Length.new([sign])
370
365
 
371
- number =
372
- if o.scientific_notation
373
- ArelExtensions::Nodes::Concat.new([
374
- Arel::Nodes::NamedFunction.new('FORMAT',[
375
- col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
376
- ]+params),
377
- o.type,
378
- Arel::Nodes::NamedFunction.new('FORMAT',[
379
- col.abs.log10.floor,
380
- 0
381
- ])
366
+ if o.scientific_notation
367
+ number = ArelExtensions::Nodes::Concat.new([
368
+ Arel::Nodes::NamedFunction.new('FORMAT',[
369
+ col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
370
+ ]+params),
371
+ o.type,
372
+ Arel::Nodes::NamedFunction.new('FORMAT',[
373
+ col.abs.log10.floor,
374
+ 0
382
375
  ])
383
- else
384
- Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
385
- end
376
+ ])
377
+ else
378
+ number = Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
379
+ end
386
380
 
387
381
  repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
388
382
  when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
@@ -405,34 +399,10 @@ module ArelExtensions
405
399
  collector
406
400
  end
407
401
 
408
- def visit_Aggregate_For_AggregateFunction o, collector
409
- if !window_supported?
410
- warn("Warning : ArelExtensions: Window Functions are not available in the current version of the DBMS.")
411
- return collector
412
- end
413
-
414
- if !o.order.empty? || !o.group.empty?
415
- collector << " OVER ("
416
- if !o.group.empty?
417
- collector << " PARTITION BY ("
418
- visit o.group, collector
419
- collector << ")"
420
- end
421
- if !o.order.empty?
422
- collector << " ORDER BY ("
423
- visit o.order, collector
424
- collector << ")"
425
- end
426
- collector << ")"
427
- end
428
- collector
429
- end
430
-
431
402
  def visit_ArelExtensions_Nodes_Std o, collector
432
403
  collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
433
404
  visit o.left, collector
434
405
  collector << ")"
435
- visit_Aggregate_For_AggregateFunction o, collector
436
406
  collector
437
407
  end
438
408
 
@@ -440,46 +410,25 @@ module ArelExtensions
440
410
  collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
441
411
  visit o.left, collector
442
412
  collector << ")"
443
- visit_Aggregate_For_AggregateFunction o, collector
444
413
  collector
445
414
  end
446
415
 
447
- # JSON if implemented only after 10.2.3 (aggregations after 10.5.0) in MariaDb and 5.7 (aggregations after 5.7.22) in MySql
416
+ # JSON if implemented only after 10.2.3 in MariaDb and 5.7 in MySql
448
417
  def json_supported?
449
- version_supported?('10.5.0', '5.7.22')
450
- end
451
-
452
- def window_supported?
453
- version_supported?('10.2.3', '8.0')
454
- end
455
-
456
- def regexp_replace_supported?
457
- version_supported?('10.0.5', '8.0')
458
- end
459
-
460
- def version_supported?(mariadb_v = '10.2.3', mysql_v = '5.7.0')
461
- conn = Arel::Table.engine.connection
462
- conn.send(:mariadb?) && \
463
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v || \
464
- conn.respond_to?(:version) && conn.send(:version) >= mariadb_v || \
465
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mariadb_v) || \
466
- !conn.send(:mariadb?) && \
467
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v || \
468
- conn.respond_to?(:version) && conn.send(:version) >= mysql_v || \
469
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mysql_v)
470
- # ideally we should parse the instance_variable @full_version because @version contains only the supposedly
471
- # corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
418
+ Arel::Table.engine.connection.send(:mariadb?) &&
419
+ Arel::Table.engine.connection.send(:version) >= '10.2.3' ||
420
+ !Arel::Table.engine.connection.send(:mariadb?) &&
421
+ Arel::Table.engine.connection.send(:version) >= '5.7.0'
472
422
  end
473
423
 
474
424
  def visit_ArelExtensions_Nodes_Json o,collector
475
425
  return super if !json_supported?
476
-
477
426
  case o.dict
478
427
  when Array
479
428
  collector << 'JSON_ARRAY('
480
429
  o.dict.each.with_index do |v,i|
481
430
  if i != 0
482
- collector << COMMA
431
+ collector << Arel::Visitors::MySQL::COMMA
483
432
  end
484
433
  collector = visit v, collector
485
434
  end
@@ -488,10 +437,10 @@ module ArelExtensions
488
437
  collector << 'JSON_OBJECT('
489
438
  o.dict.each.with_index do |(k,v),i|
490
439
  if i != 0
491
- collector << COMMA
440
+ collector << Arel::Visitors::MySQL::COMMA
492
441
  end
493
442
  collector = visit k, collector
494
- collector << COMMA
443
+ collector << Arel::Visitors::MySQL::COMMA
495
444
  collector = visit v, collector
496
445
  end
497
446
  collector << ')'
@@ -505,7 +454,7 @@ module ArelExtensions
505
454
  collector << 'JSON_MERGE_PATCH('
506
455
  o.expressions.each.with_index do |v,i|
507
456
  if i != 0
508
- collector << COMMA
457
+ collector << Arel::Visitors::MySQL::COMMA
509
458
  end
510
459
  collector = visit v, collector
511
460
  end
@@ -516,7 +465,7 @@ module ArelExtensions
516
465
  def visit_ArelExtensions_Nodes_JsonGet o,collector
517
466
  collector << 'JSON_EXTRACT('
518
467
  collector = visit o.dict, collector
519
- collector << COMMA
468
+ collector << Arel::Visitors::MySQL::COMMA
520
469
  if o.key.is_a?(Integer)
521
470
  collector << "\"$[#{o.key}]\""
522
471
  else
@@ -529,13 +478,13 @@ module ArelExtensions
529
478
  def visit_ArelExtensions_Nodes_JsonSet o,collector
530
479
  collector << 'JSON_SET('
531
480
  collector = visit o.dict, collector
532
- collector << COMMA
481
+ collector << Arel::Visitors::MySQL::COMMA
533
482
  if o.key.is_a?(Integer)
534
483
  collector << "\"$[#{o.key}]\""
535
484
  else
536
485
  collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
537
486
  end
538
- collector << COMMA
487
+ collector << Arel::Visitors::MySQL::COMMA
539
488
  collector = visit o.value, collector
540
489
  collector << ')'
541
490
  collector
@@ -543,7 +492,6 @@ module ArelExtensions
543
492
 
544
493
  def visit_ArelExtensions_Nodes_JsonGroup o, collector
545
494
  return super if !json_supported?
546
-
547
495
  if o.as_array
548
496
  collector << 'JSON_ARRAYAGG('
549
497
  collector = visit o.dict, collector
@@ -554,11 +502,11 @@ module ArelExtensions
554
502
  collector << 'JSON_MERGE_PATCH(' if o.dict.length > 1
555
503
  o.dict.each.with_index do |(k,v),i|
556
504
  if i != 0
557
- collector << COMMA
505
+ collector << Arel::Visitors::MySQL::COMMA
558
506
  end
559
507
  collector << 'JSON_OBJECTAGG('
560
508
  collector = visit k, collector
561
- collector << COMMA
509
+ collector << Arel::Visitors::MySQL::COMMA
562
510
  collector = visit v, collector
563
511
  collector << ')'
564
512
  end
@@ -571,6 +519,7 @@ module ArelExtensions
571
519
  end
572
520
  collector
573
521
  end
522
+
574
523
  end
575
524
  end
576
525
  end