arel_extensions 2.0.21 → 2.2.2

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -2
  3. data/.github/workflows/publish.yml +29 -0
  4. data/.github/workflows/release.yml +30 -0
  5. data/.github/workflows/ruby.yml +377 -80
  6. data/.gitignore +7 -6
  7. data/.rubocop.yml +62 -1
  8. data/CONTRIBUTING.md +102 -0
  9. data/Gemfile +2 -23
  10. data/NEWS.md +89 -0
  11. data/README.md +228 -84
  12. data/Rakefile +11 -4
  13. data/TODO +0 -1
  14. data/appveyor.yml +60 -22
  15. data/arel_extensions.gemspec +11 -12
  16. data/bin/build +15 -0
  17. data/bin/compose +6 -0
  18. data/bin/publish +8 -0
  19. data/dev/arelx.dockerfile +44 -0
  20. data/dev/compose.yaml +71 -0
  21. data/dev/postgres.dockerfile +5 -0
  22. data/dev/rbenv +189 -0
  23. data/gemfiles/rails3.gemfile +10 -10
  24. data/gemfiles/rails4_2.gemfile +38 -0
  25. data/gemfiles/rails5.gemfile +29 -0
  26. data/gemfiles/rails5_1_4.gemfile +13 -13
  27. data/gemfiles/rails5_2.gemfile +16 -14
  28. data/gemfiles/rails6.gemfile +18 -15
  29. data/gemfiles/rails6_1.gemfile +18 -15
  30. data/gemfiles/rails7.gemfile +33 -0
  31. data/gemfiles/rails7_1.gemfile +33 -0
  32. data/gemfiles/rails7_2.gemfile +33 -0
  33. data/gemspecs/arel_extensions-v1.gemspec +12 -13
  34. data/gemspecs/arel_extensions-v2.gemspec +11 -12
  35. data/init/mssql.sql +0 -0
  36. data/init/mysql.sql +0 -0
  37. data/init/oracle.sql +0 -0
  38. data/init/postgresql.sql +0 -0
  39. data/init/sqlite.sql +0 -0
  40. data/lib/arel_extensions/aliases.rb +14 -0
  41. data/lib/arel_extensions/attributes.rb +10 -2
  42. data/lib/arel_extensions/boolean_functions.rb +2 -4
  43. data/lib/arel_extensions/common_sql_functions.rb +12 -12
  44. data/lib/arel_extensions/comparators.rb +14 -14
  45. data/lib/arel_extensions/date_duration.rb +14 -9
  46. data/lib/arel_extensions/helpers.rb +62 -0
  47. data/lib/arel_extensions/insert_manager.rb +19 -17
  48. data/lib/arel_extensions/math.rb +48 -45
  49. data/lib/arel_extensions/math_functions.rb +18 -18
  50. data/lib/arel_extensions/nodes/abs.rb +0 -0
  51. data/lib/arel_extensions/nodes/aggregate_function.rb +0 -0
  52. data/lib/arel_extensions/nodes/blank.rb +1 -1
  53. data/lib/arel_extensions/nodes/case.rb +10 -12
  54. data/lib/arel_extensions/nodes/cast.rb +6 -6
  55. data/lib/arel_extensions/nodes/ceil.rb +0 -0
  56. data/lib/arel_extensions/nodes/change_case.rb +0 -0
  57. data/lib/arel_extensions/nodes/coalesce.rb +1 -1
  58. data/lib/arel_extensions/nodes/collate.rb +9 -9
  59. data/lib/arel_extensions/nodes/concat.rb +2 -2
  60. data/lib/arel_extensions/nodes/date_diff.rb +33 -14
  61. data/lib/arel_extensions/nodes/duration.rb +0 -0
  62. data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
  63. data/lib/arel_extensions/nodes/floor.rb +0 -0
  64. data/lib/arel_extensions/nodes/format.rb +3 -2
  65. data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
  66. data/lib/arel_extensions/nodes/formatted_number.rb +2 -2
  67. data/lib/arel_extensions/nodes/function.rb +22 -26
  68. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  69. data/lib/arel_extensions/nodes/json.rb +15 -9
  70. data/lib/arel_extensions/nodes/length.rb +6 -0
  71. data/lib/arel_extensions/nodes/levenshtein_distance.rb +1 -1
  72. data/lib/arel_extensions/nodes/locate.rb +1 -1
  73. data/lib/arel_extensions/nodes/log10.rb +0 -0
  74. data/lib/arel_extensions/nodes/matches.rb +1 -1
  75. data/lib/arel_extensions/nodes/md5.rb +0 -0
  76. data/lib/arel_extensions/nodes/power.rb +0 -0
  77. data/lib/arel_extensions/nodes/rand.rb +0 -0
  78. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  79. data/lib/arel_extensions/nodes/replace.rb +2 -10
  80. data/lib/arel_extensions/nodes/rollup.rb +36 -0
  81. data/lib/arel_extensions/nodes/round.rb +0 -0
  82. data/lib/arel_extensions/nodes/select.rb +10 -0
  83. data/lib/arel_extensions/nodes/soundex.rb +2 -2
  84. data/lib/arel_extensions/nodes/std.rb +0 -0
  85. data/lib/arel_extensions/nodes/substring.rb +1 -1
  86. data/lib/arel_extensions/nodes/sum.rb +0 -0
  87. data/lib/arel_extensions/nodes/then.rb +1 -1
  88. data/lib/arel_extensions/nodes/trim.rb +2 -2
  89. data/lib/arel_extensions/nodes/union.rb +5 -5
  90. data/lib/arel_extensions/nodes/union_all.rb +4 -4
  91. data/lib/arel_extensions/nodes/wday.rb +0 -0
  92. data/lib/arel_extensions/nodes.rb +0 -0
  93. data/lib/arel_extensions/null_functions.rb +16 -0
  94. data/lib/arel_extensions/predications.rb +10 -10
  95. data/lib/arel_extensions/railtie.rb +1 -1
  96. data/lib/arel_extensions/set_functions.rb +3 -3
  97. data/lib/arel_extensions/string_functions.rb +19 -10
  98. data/lib/arel_extensions/tasks.rb +2 -2
  99. data/lib/arel_extensions/version.rb +1 -1
  100. data/lib/arel_extensions/visitors/convert_format.rb +0 -0
  101. data/lib/arel_extensions/visitors/ibm_db.rb +20 -20
  102. data/lib/arel_extensions/visitors/mssql.rb +394 -169
  103. data/lib/arel_extensions/visitors/mysql.rb +238 -151
  104. data/lib/arel_extensions/visitors/oracle.rb +170 -131
  105. data/lib/arel_extensions/visitors/oracle12.rb +16 -16
  106. data/lib/arel_extensions/visitors/postgresql.rb +170 -140
  107. data/lib/arel_extensions/visitors/sqlite.rb +88 -87
  108. data/lib/arel_extensions/visitors/to_sql.rb +185 -156
  109. data/lib/arel_extensions/visitors.rb +73 -60
  110. data/lib/arel_extensions.rb +173 -36
  111. data/test/arelx_test_helper.rb +49 -1
  112. data/test/database.yml +13 -7
  113. data/test/real_db_test.rb +101 -83
  114. data/test/support/fake_record.rb +8 -2
  115. data/test/test_comparators.rb +5 -5
  116. data/test/visitors/test_bulk_insert_oracle.rb +5 -5
  117. data/test/visitors/test_bulk_insert_sqlite.rb +5 -5
  118. data/test/visitors/test_bulk_insert_to_sql.rb +5 -5
  119. data/test/visitors/test_oracle.rb +14 -14
  120. data/test/visitors/test_to_sql.rb +121 -93
  121. data/test/with_ar/all_agnostic_test.rb +630 -320
  122. data/test/with_ar/insert_agnostic_test.rb +25 -18
  123. data/test/with_ar/test_bulk_sqlite.rb +11 -7
  124. data/test/with_ar/test_math_sqlite.rb +18 -14
  125. data/test/with_ar/test_string_mysql.rb +26 -22
  126. data/test/with_ar/test_string_sqlite.rb +26 -22
  127. data/version_v1.rb +1 -1
  128. data/version_v2.rb +1 -1
  129. metadata +24 -26
  130. data/.travis/oracle/download.js +0 -152
  131. data/.travis/oracle/download.sh +0 -30
  132. data/.travis/oracle/download_ojdbc.js +0 -116
  133. data/.travis/oracle/install.sh +0 -34
  134. data/.travis/setup_accounts.sh +0 -9
  135. data/.travis/sqlite3/extension-functions.sh +0 -6
  136. data/.travis.yml +0 -193
  137. data/gemfiles/rails4.gemfile +0 -29
  138. data/gemfiles/rails5_0.gemfile +0 -29
@@ -8,30 +8,77 @@ module ArelExtensions
8
8
 
9
9
  DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
10
10
  '%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
11
- '%d' => '%d', '%e' => '%e', '%j' => '%j', '%w' => '%w', '%A' => '%W', # day, weekday
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
12
13
  '%H' => '%H', '%k' => '%k', '%I' => '%I', '%l' => '%l', '%P' => '%p', '%p' => '%p', # hours
13
14
  '%M' => '%i', '%S' => '%S', '%L' => '', '%N' => '%f', '%z' => ''
14
15
  }.freeze
15
16
 
17
+ # This helper method did not exist in rails < 5.2
18
+ if !Arel::Visitors::MySQL.method_defined?(:collect_nodes_for)
19
+ def collect_nodes_for(nodes, collector, spacer, connector = ", ")
20
+ if nodes&.any?
21
+ collector << spacer
22
+ inject_join nodes, collector, connector
23
+ end
24
+ end
25
+ end
26
+
27
+ # The whole purpose of this override is to fix the behavior of RollUp.
28
+ # All other databases treat RollUp sanely, execpt MySQL which requires
29
+ # that it figures as the last element of a GROUP BY.
30
+ def visit_Arel_Nodes_SelectCore(o, collector)
31
+ collector << "SELECT"
32
+
33
+ collector = collect_optimizer_hints(o, collector) if self.respond_to?(:collect_optimizer_hinsts)
34
+ collector = maybe_visit o.set_quantifier, collector
35
+
36
+ collect_nodes_for o.projections, collector, " "
37
+
38
+ if o.source && !o.source.empty?
39
+ collector << " FROM "
40
+ collector = visit o.source, collector
41
+ end
42
+
43
+ # The actual work
44
+ groups = o.groups
45
+ rollup = groups.select { |g| g.expr.class == Arel::Nodes::RollUp }.map { |r| r.expr.value }
46
+ if rollup && !rollup.empty?
47
+ groups = o.groups.reject { |g| g.expr.class == Arel::Nodes::RollUp }
48
+ groups << Arel::Nodes::RollUp.new(rollup)
49
+ end
50
+ # FIN
51
+
52
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
53
+ collect_nodes_for groups, collector, " GROUP BY " # Look ma, I'm viring a group
54
+ collect_nodes_for o.havings, collector, " HAVING ", " AND "
55
+ collect_nodes_for o.windows, collector, " WINDOW "
56
+
57
+ if o.respond_to?(:comment)
58
+ maybe_visit o.comment, collector
59
+ else
60
+ collector
61
+ end
62
+ end
16
63
 
17
64
  # Math functions
18
65
  def visit_ArelExtensions_Nodes_Log10 o, collector
19
- collector << "LOG10("
20
- o.expressions.each_with_index { |arg, i|
21
- collector << Arel::Visitors::ToSql::COMMA if i != 0
22
- collector = visit arg, collector
23
- }
24
- collector << ")"
25
- collector
66
+ collector << 'LOG10('
67
+ o.expressions.each_with_index { |arg, i|
68
+ collector << Arel::Visitors::ToSql::COMMA if i != 0
69
+ collector = visit arg, collector
70
+ }
71
+ collector << ')'
72
+ collector
26
73
  end
27
74
 
28
75
  def visit_ArelExtensions_Nodes_Power o, collector
29
- collector << "POW("
76
+ collector << 'POW('
30
77
  o.expressions.each_with_index { |arg, i|
31
78
  collector << Arel::Visitors::ToSql::COMMA if i != 0
32
79
  collector = visit arg, collector
33
80
  }
34
- collector << ")"
81
+ collector << ')'
35
82
  collector
36
83
  end
37
84
 
@@ -44,10 +91,9 @@ module ArelExtensions
44
91
  collector << ')'
45
92
  if o.escape
46
93
  collector << ' ESCAPE '
47
- visit o.escape, collector
48
- else
49
- collector
94
+ collector = visit o.escape, collector
50
95
  end
96
+ collector
51
97
  end
52
98
 
53
99
  def visit_ArelExtensions_Nodes_AiMatches o, collector
@@ -56,10 +102,9 @@ module ArelExtensions
56
102
  collector = visit o.right.ai_collate, collector
57
103
  if o.escape
58
104
  collector << ' ESCAPE '
59
- visit o.escape, collector
60
- else
61
- collector
105
+ collector = visit o.escape, collector
62
106
  end
107
+ collector
63
108
  end
64
109
 
65
110
  def visit_ArelExtensions_Nodes_AiIMatches o, collector
@@ -68,22 +113,20 @@ module ArelExtensions
68
113
  collector = visit o.right.ai_collate, collector
69
114
  if o.escape
70
115
  collector << ' ESCAPE '
71
- visit o.escape, collector
72
- else
73
- collector
116
+ collector = visit o.escape, collector
74
117
  end
118
+ collector
75
119
  end
76
120
 
77
121
  def visit_ArelExtensions_Nodes_SMatches o, collector
78
- collector = visit o.left.collate, collector
79
- collector << ' LIKE '
80
- collector = visit o.right.collate, collector
81
- if o.escape
82
- collector << ' ESCAPE '
83
- visit o.escape, collector
84
- else
85
- collector
86
- end
122
+ collector = visit o.left.collate, collector
123
+ collector << ' LIKE '
124
+ collector = visit o.right.collate, collector
125
+ if o.escape
126
+ collector << ' ESCAPE '
127
+ collector = visit o.escape, collector
128
+ end
129
+ collector
87
130
  end
88
131
 
89
132
  def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
@@ -94,10 +137,9 @@ module ArelExtensions
94
137
  collector << ')'
95
138
  if o.escape
96
139
  collector << ' ESCAPE '
97
- visit o.escape, collector
98
- else
99
- collector
140
+ collector = visit o.escape, collector
100
141
  end
142
+ collector
101
143
  end
102
144
 
103
145
  def visit_ArelExtensions_Nodes_Collate o, collector
@@ -105,7 +147,7 @@ module ArelExtensions
105
147
  case o.expressions.first
106
148
  when Arel::Attributes::Attribute
107
149
  case o.option
108
- when 'latin1','utf8'
150
+ when 'latin1', 'utf8'
109
151
  o.option
110
152
  else
111
153
  Arel::Table.engine.connection.charset || 'utf8'
@@ -116,10 +158,10 @@ module ArelExtensions
116
158
  collector = visit o.expressions.first, collector
117
159
  collector <<
118
160
  if o.ai
119
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
161
+ " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : "#{charset}_unicode_ci"}"
120
162
  # doesn't work in latin1
121
163
  elsif o.ci
122
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
164
+ " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : "#{charset}_unicode_ci"}"
123
165
  else
124
166
  " COLLATE #{charset}_bin"
125
167
  end
@@ -127,27 +169,32 @@ module ArelExtensions
127
169
  end
128
170
 
129
171
  def visit_ArelExtensions_Nodes_Concat o, collector
130
- collector << "CONCAT("
172
+ collector << 'CONCAT('
131
173
  o.expressions.each_with_index { |arg, i|
132
174
  collector << COMMA if i != 0
133
- if (arg.is_a?(Numeric)) || (arg.is_a?(Arel::Attributes::Attribute))
134
- collector << "CAST("
175
+ if arg.is_a?(Numeric) || arg.is_a?(Arel::Attributes::Attribute)
176
+ collector << 'CAST('
135
177
  collector = visit arg, collector
136
- collector << " AS char)"
178
+ collector << ' AS char)'
137
179
  else
138
180
  collector = visit arg, collector
139
181
  end
140
182
  }
141
- collector << ")"
183
+ collector << ')'
142
184
  collector
143
185
  end
144
186
 
187
+ def visit_Arel_Nodes_RollUp(o, collector)
188
+ visit o.expr, collector
189
+ collector << " WITH ROLLUP"
190
+ end
191
+
145
192
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
146
- collector << "GROUP_CONCAT("
193
+ collector << 'GROUP_CONCAT('
147
194
  collector = visit o.left, collector
148
195
  if !o.order.blank?
149
196
  collector << ' ORDER BY '
150
- o.order.each_with_index do |order,i|
197
+ o.order.each_with_index do |order, i|
151
198
  collector << Arel::Visitors::ToSql::COMMA if i != 0
152
199
  collector = visit order, collector
153
200
  end
@@ -156,77 +203,108 @@ module ArelExtensions
156
203
  collector << ' SEPARATOR '
157
204
  collector = visit o.separator, collector
158
205
  end
159
- collector << ")"
206
+ collector << ')'
160
207
  collector
161
208
  end
162
209
 
163
210
  def visit_ArelExtensions_Nodes_Trim o, collector
164
- collector << 'TRIM(' # BOTH
165
- collector = visit o.right, collector
166
- collector << " FROM "
167
- collector = visit o.left, collector
168
- collector << ")"
169
- collector
211
+ collector << 'TRIM(' # BOTH
212
+ collector = visit o.right, collector
213
+ collector << ' FROM '
214
+ collector = visit o.left, collector
215
+ collector << ')'
216
+ collector
170
217
  end
171
218
 
172
219
  def visit_ArelExtensions_Nodes_Ltrim o, collector
173
- collector << 'TRIM(LEADING '
174
- collector = visit o.right, collector
175
- collector << " FROM "
176
- collector = visit o.left, collector
177
- collector << ")"
178
- collector
220
+ collector << 'TRIM(LEADING '
221
+ collector = visit o.right, collector
222
+ collector << ' FROM '
223
+ collector = visit o.left, collector
224
+ collector << ')'
225
+ collector
179
226
  end
180
227
 
181
228
  def visit_ArelExtensions_Nodes_Rtrim o, collector
182
229
  collector << 'TRIM(TRAILING '
183
230
  collector = visit o.right, collector
184
- collector << " FROM "
231
+ collector << ' FROM '
185
232
  collector = visit o.left, collector
186
- collector << ")"
233
+ collector << ')'
187
234
  collector
188
235
  end
189
236
 
190
237
  def visit_ArelExtensions_Nodes_Repeat o, collector
191
- collector << "REPEAT("
238
+ collector << 'REPEAT('
192
239
  o.expressions.each_with_index { |arg, i|
193
240
  collector << Arel::Visitors::ToSql::COMMA if i != 0
194
241
  collector = visit arg, collector
195
242
  }
196
- collector << ")"
243
+ collector << ')'
197
244
  collector
198
245
  end
199
246
 
200
247
  def visit_ArelExtensions_Nodes_RegexpReplace o, collector
201
248
  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")
249
+ warn('Warning: ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash')
203
250
  end
204
- super(o,collector)
251
+ super(o, collector)
205
252
  end
206
253
 
207
254
  def visit_ArelExtensions_Nodes_Format o, collector
208
- case o.col_type
255
+ # One use case we met is
256
+ # `case…when…then(valid_date).else(Arel.null).format(…)`.
257
+ #
258
+ # In this case, `o.col_type` is `nil` but we have a legitimate type in
259
+ # the expression to be formatted. The following is a best effort to
260
+ # infer the proper type.
261
+ first = o.expressions[0]
262
+ type =
263
+ o.col_type.nil? \
264
+ && (first.respond_to?(:return_type) && !first&.return_type.nil?) \
265
+ ? first&.return_type \
266
+ : o.col_type
267
+
268
+ case type
209
269
  when :date, :datetime, :time
210
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
211
- collector << "DATE_FORMAT("
212
- collector = visit o.left, collector
213
- collector << COMMA
214
- collector = visit Arel::Nodes.build_quoted(fmt), collector
215
- collector << ")"
270
+ visit_ArelExtensions_Nodes_FormattedDate o, collector
216
271
  when :integer, :float, :decimal
217
- collector << "FORMAT("
272
+ collector << 'FORMAT('
218
273
  collector = visit o.left, collector
219
274
  collector << Arel::Visitors::ToSql::COMMA
220
275
  collector << '2'
221
276
  collector << Arel::Visitors::ToSql::COMMA
222
277
  collector = visit o.right, collector
223
- collector << ")"
278
+ collector << ')'
224
279
  else
225
280
  collector = visit o.left, collector
226
281
  end
227
282
  collector
228
283
  end
229
284
 
285
+ def visit_ArelExtensions_Nodes_FormattedDate o, collector
286
+ fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
287
+ collector << 'DATE_FORMAT('
288
+ collector << 'CONVERT_TZ(' if o.time_zone
289
+ collector = visit o.left, collector
290
+ case o.time_zone
291
+ when Hash
292
+ src_tz, dst_tz = o.time_zone.first
293
+ collector << COMMA
294
+ collector = visit Arel.quoted(src_tz), collector
295
+ collector << COMMA
296
+ collector = visit Arel.quoted(dst_tz), collector
297
+ collector << ')'
298
+ when String
299
+ collector << COMMA << "'UTC'" << COMMA
300
+ collector = visit Arel.quoted(o.time_zone), collector
301
+ collector << ')'
302
+ end
303
+ collector << COMMA
304
+ collector = visit Arel.quoted(fmt), collector
305
+ collector << ')'
306
+ end
307
+
230
308
  def visit_ArelExtensions_Nodes_DateDiff o, collector
231
309
  case o.right_node_type
232
310
  when :ruby_date, :ruby_time, :date, :datetime, :time
@@ -238,7 +316,7 @@ module ArelExtensions
238
316
  collector = visit o.right, collector
239
317
  collector << COMMA
240
318
  collector = visit o.left, collector
241
- collector << ")"
319
+ collector << ')'
242
320
  else
243
321
  collector << '('
244
322
  collector = visit o.left, collector
@@ -258,81 +336,79 @@ module ArelExtensions
258
336
  end
259
337
 
260
338
  def visit_ArelExtensions_Nodes_DateAdd o, collector
261
- collector << "DATE_ADD("
339
+ collector << 'DATE_ADD('
262
340
  collector = visit o.left, collector
263
341
  collector << COMMA
264
342
  collector = visit o.mysql_value(o.right), collector
265
- collector << ")"
343
+ collector << ')'
266
344
  collector
267
345
  end
268
346
 
269
347
  def visit_ArelExtensions_Nodes_Duration o, collector
270
348
  if o.left == 'wd'
271
- collector << "(WEEKDAY("
349
+ collector << '(WEEKDAY('
272
350
  collector = visit o.right, collector
273
- collector << ") + 1) % 7"
351
+ collector << ') + 1) % 7'
274
352
  else
275
353
  if o.with_interval
276
- case o.left
277
- when 'd','m','y'
278
- interval = 'DAY'
279
- when 'h','mn','s'
280
- interval = 'SECOND'
281
- when /i\z/
282
- interval = DATE_MAPPING[o.left[0..-2]]
283
- else
284
- interval = nil
285
- end
354
+ interval =
355
+ case o.left
356
+ when 'd', 'm', 'y'
357
+ 'DAY'
358
+ when 'h', 'mn', 's'
359
+ 'SECOND'
360
+ when /i\z/
361
+ DATE_MAPPING[o.left[0..-2]]
362
+ end
286
363
  end
287
- collector << " INTERVAL " if o.with_interval && interval
364
+ collector << ' INTERVAL ' if o.with_interval && interval
288
365
  collector << "#{DATE_MAPPING[o.left]}("
289
366
  collector = visit o.right, collector
290
- collector << ")"
367
+ collector << ')'
291
368
  collector << " #{interval} " if o.with_interval && interval
292
369
  end
293
370
  collector
294
371
  end
295
372
 
296
373
  def visit_ArelExtensions_Nodes_IsNull o, collector
297
- collector << "ISNULL("
374
+ collector << 'ISNULL('
298
375
  collector = visit o.expr, collector
299
- collector << ")"
376
+ collector << ')'
300
377
  collector
301
378
  end
302
379
 
303
380
  def visit_ArelExtensions_Nodes_IsNotNull o, collector
304
- collector << "NOT ISNULL("
381
+ collector << 'NOT ISNULL('
305
382
  collector = visit o.expr, collector
306
- collector << ")"
383
+ collector << ')'
307
384
  collector
308
385
  end
309
386
 
310
387
  def visit_ArelExtensions_Nodes_Wday o, collector
311
- collector << "(WEEKDAY("
388
+ collector << '(WEEKDAY('
312
389
  collector = visit o.date, collector
313
- collector << ") + 1) % 7"
390
+ collector << ') + 1) % 7'
314
391
  collector
315
392
  end
316
393
 
317
394
  def visit_ArelExtensions_Nodes_Cast o, collector
318
- collector << "CAST("
319
- collector = visit o.left, collector
320
- collector << " AS "
321
395
  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
- )
334
- collector = visit as_attr, collector
335
- collector << ")"
396
+ case o.as_attr
397
+ when :binary then 'binary'
398
+ when :date then 'date'
399
+ when :datetime then 'datetime'
400
+ when :int then 'signed'
401
+ when :number, :decimal then 'decimal(20,6)'
402
+ when :string then 'char'
403
+ when :time then 'time'
404
+ else o.as_attr.to_s
405
+ end
406
+
407
+ collector << 'CAST('
408
+ collector = visit o.left, collector
409
+ collector << ' AS '
410
+ collector = visit Arel::Nodes::SqlLiteral.new(as_attr), collector
411
+ collector << ')'
336
412
  collector
337
413
  end
338
414
 
@@ -342,7 +418,7 @@ module ArelExtensions
342
418
  o = o.dup
343
419
  o.orders = []
344
420
  end
345
- old_visit_Arel_Nodes_SelectStatement(o,collector)
421
+ old_visit_Arel_Nodes_SelectStatement(o, collector)
346
422
  end
347
423
 
348
424
  alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
@@ -354,16 +430,22 @@ module ArelExtensions
354
430
  else
355
431
  collector = visit o.left, collector
356
432
  end
357
- collector << " AS `"
433
+ collector << ' AS '
434
+
435
+ # sometimes these values are already quoted, if they are, don't double quote it
436
+ quote = o.right.is_a?(Arel::Nodes::SqlLiteral) && o.right[0] != '`' && o.right[-1] != '`'
437
+
438
+ collector << '`' if quote
358
439
  collector = visit o.right, collector
359
- collector << "`"
440
+ collector << '`' if quote
441
+
360
442
  collector
361
443
  end
362
444
 
363
445
  def visit_ArelExtensions_Nodes_FormattedNumber o, collector
364
446
  col = o.left.coalesce(0)
365
- params = o.locale ? [o.precision,Arel::Nodes.build_quoted(o.locale)] : [o.precision]
366
- sign = ArelExtensions::Nodes::Case.new.when(col<0).
447
+ params = o.locale ? [o.precision, Arel.quoted(o.locale)] : [o.precision]
448
+ sign = Arel.when(col < 0).
367
449
  then('-').
368
450
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
369
451
  sign_length = ArelExtensions::Nodes::Length.new([sign])
@@ -371,28 +453,33 @@ module ArelExtensions
371
453
  number =
372
454
  if o.scientific_notation
373
455
  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),
456
+ Arel::Nodes::NamedFunction.new('FORMAT', [
457
+ col.abs / Arel.quoted(10).pow(col.abs.log10.floor)
458
+ ] + params),
377
459
  o.type,
378
- Arel::Nodes::NamedFunction.new('FORMAT',[
460
+ Arel::Nodes::NamedFunction.new('FORMAT', [
379
461
  col.abs.log10.floor,
380
462
  0
381
463
  ])
382
464
  ])
383
465
  else
384
- Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
466
+ Arel::Nodes::NamedFunction.new('FORMAT', [col.abs] + params)
385
467
  end
386
468
 
387
- repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
388
- when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
389
- then(Arel::Nodes.build_quoted(
390
- o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
391
- ).repeat(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length))
392
- ).
393
- else('')
394
- before = (!o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
395
- middle = (o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
469
+ repeated_char =
470
+ if o.width == 0
471
+ Arel.quoted('')
472
+ else
473
+ Arel
474
+ .when(Arel.quoted(o.width).abs - (number.length + sign_length) > 0)
475
+ .then(Arel.quoted(
476
+ o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
477
+ ).repeat(Arel.quoted(o.width).abs - (number.length + sign_length))
478
+ )
479
+ .else('')
480
+ end
481
+ before = !o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
482
+ middle = o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
396
483
  after = o.flags.include?('-') ? repeated_char : ''
397
484
  full_number = ArelExtensions::Nodes::Concat.new([
398
485
  before,
@@ -401,45 +488,45 @@ module ArelExtensions
401
488
  number,
402
489
  after
403
490
  ])
404
- collector = visit ArelExtensions::Nodes::Concat.new([Arel::Nodes.build_quoted(o.prefix),full_number,Arel::Nodes.build_quoted(o.suffix)]), collector
491
+ collector = visit ArelExtensions::Nodes::Concat.new([Arel.quoted(o.prefix), full_number, Arel.quoted(o.suffix)]), collector
405
492
  collector
406
493
  end
407
494
 
408
495
  def visit_Aggregate_For_AggregateFunction o, collector
409
496
  if !window_supported?
410
- warn("Warning : ArelExtensions: Window Functions are not available in the current version of the DBMS.")
411
- return collector
497
+ warn('Warning: ArelExtensions: Window Functions are not available in the current version of the DBMS.')
498
+ return collector
412
499
  end
413
500
 
414
501
  if !o.order.empty? || !o.group.empty?
415
- collector << " OVER ("
502
+ collector << ' OVER ('
416
503
  if !o.group.empty?
417
- collector << " PARTITION BY ("
504
+ collector << ' PARTITION BY ('
418
505
  visit o.group, collector
419
- collector << ")"
506
+ collector << ')'
420
507
  end
421
508
  if !o.order.empty?
422
- collector << " ORDER BY ("
509
+ collector << ' ORDER BY ('
423
510
  visit o.order, collector
424
- collector << ")"
511
+ collector << ')'
425
512
  end
426
- collector << ")"
513
+ collector << ')'
427
514
  end
428
515
  collector
429
516
  end
430
517
 
431
518
  def visit_ArelExtensions_Nodes_Std o, collector
432
- collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
519
+ collector << (o.unbiased_estimator ? 'STDDEV_SAMP(' : 'STDDEV_POP(')
433
520
  visit o.left, collector
434
- collector << ")"
521
+ collector << ')'
435
522
  visit_Aggregate_For_AggregateFunction o, collector
436
523
  collector
437
524
  end
438
525
 
439
526
  def visit_ArelExtensions_Nodes_Variance o, collector
440
- collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
527
+ collector << (o.unbiased_estimator ? 'VAR_SAMP(' : 'VAR_POP(')
441
528
  visit o.left, collector
442
- collector << ")"
529
+ collector << ')'
443
530
  visit_Aggregate_For_AggregateFunction o, collector
444
531
  collector
445
532
  end
@@ -471,13 +558,13 @@ module ArelExtensions
471
558
  # corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
472
559
  end
473
560
 
474
- def visit_ArelExtensions_Nodes_Json o,collector
561
+ def visit_ArelExtensions_Nodes_Json o, collector
475
562
  return super if !json_supported?
476
563
 
477
564
  case o.dict
478
565
  when Array
479
566
  collector << 'JSON_ARRAY('
480
- o.dict.each.with_index do |v,i|
567
+ o.dict.each.with_index do |v, i|
481
568
  if i != 0
482
569
  collector << COMMA
483
570
  end
@@ -486,7 +573,7 @@ module ArelExtensions
486
573
  collector << ')'
487
574
  when Hash
488
575
  collector << 'JSON_OBJECT('
489
- o.dict.each.with_index do |(k,v),i|
576
+ o.dict.each.with_index do |(k, v), i|
490
577
  if i != 0
491
578
  collector << COMMA
492
579
  end
@@ -501,9 +588,9 @@ module ArelExtensions
501
588
  collector
502
589
  end
503
590
 
504
- def visit_ArelExtensions_Nodes_JsonMerge o,collector
591
+ def visit_ArelExtensions_Nodes_JsonMerge o, collector
505
592
  collector << 'JSON_MERGE_PATCH('
506
- o.expressions.each.with_index do |v,i|
593
+ o.expressions.each.with_index do |v, i|
507
594
  if i != 0
508
595
  collector << COMMA
509
596
  end
@@ -513,27 +600,27 @@ module ArelExtensions
513
600
  collector
514
601
  end
515
602
 
516
- def visit_ArelExtensions_Nodes_JsonGet o,collector
603
+ def visit_ArelExtensions_Nodes_JsonGet o, collector
517
604
  collector << 'JSON_EXTRACT('
518
605
  collector = visit o.dict, collector
519
606
  collector << COMMA
520
607
  if o.key.is_a?(Integer)
521
608
  collector << "\"$[#{o.key}]\""
522
609
  else
523
- collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
610
+ collector = visit Arel.quoted('$.') + o.key, collector
524
611
  end
525
612
  collector << ')'
526
613
  collector
527
614
  end
528
615
 
529
- def visit_ArelExtensions_Nodes_JsonSet o,collector
616
+ def visit_ArelExtensions_Nodes_JsonSet o, collector
530
617
  collector << 'JSON_SET('
531
618
  collector = visit o.dict, collector
532
619
  collector << COMMA
533
620
  if o.key.is_a?(Integer)
534
621
  collector << "\"$[#{o.key}]\""
535
622
  else
536
- collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
623
+ collector = visit Arel.quoted('$.') + o.key, collector
537
624
  end
538
625
  collector << COMMA
539
626
  collector = visit o.value, collector
@@ -552,7 +639,7 @@ module ArelExtensions
552
639
  case o.dict
553
640
  when Hash
554
641
  collector << 'JSON_MERGE_PATCH(' if o.dict.length > 1
555
- o.dict.each.with_index do |(k,v),i|
642
+ o.dict.each.with_index do |(k, v), i|
556
643
  if i != 0
557
644
  collector << COMMA
558
645
  end