arel_extensions 1.3.5 → 2.0.0.rc3

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