arel_extensions 2.4.0 → 2.5.0

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +131 -5
  4. data/Makefile +31 -1
  5. data/NEWS.md +15 -0
  6. data/README.md +11 -2
  7. data/Rakefile +5 -3
  8. data/arel_extensions.gemspec +3 -5
  9. data/gemfiles/rails5.gemfile +15 -8
  10. data/gemfiles/rails5_1_4.gemfile +11 -9
  11. data/gemfiles/rails5_2.gemfile +16 -9
  12. data/gemfiles/rails6.gemfile +13 -7
  13. data/gemfiles/rails6_1.gemfile +13 -7
  14. data/gemfiles/rails7.gemfile +15 -9
  15. data/gemfiles/rails7_1.gemfile +15 -8
  16. data/gemfiles/rails7_2.gemfile +12 -6
  17. data/gemfiles/rails8.gemfile +7 -7
  18. data/gemfiles/rails8_1.gemfile +4 -4
  19. data/gemspecs/arel_extensions-v1.gemspec +3 -5
  20. data/gemspecs/arel_extensions-v2.gemspec +3 -5
  21. data/lib/arel_extensions/aliases.rb +3 -3
  22. data/lib/arel_extensions/attributes.rb +2 -0
  23. data/lib/arel_extensions/boolean_functions.rb +9 -7
  24. data/lib/arel_extensions/common_sql_functions.rb +5 -3
  25. data/lib/arel_extensions/comparators.rb +6 -4
  26. data/lib/arel_extensions/date_duration.rb +2 -0
  27. data/lib/arel_extensions/helpers.rb +17 -17
  28. data/lib/arel_extensions/insert_manager.rb +5 -1
  29. data/lib/arel_extensions/math.rb +40 -44
  30. data/lib/arel_extensions/math_functions.rb +28 -30
  31. data/lib/arel_extensions/nodes/aggregate_function.rb +4 -4
  32. data/lib/arel_extensions/nodes/blank.rb +6 -4
  33. data/lib/arel_extensions/nodes/case.rb +15 -12
  34. data/lib/arel_extensions/nodes/cast.rb +3 -5
  35. data/lib/arel_extensions/nodes/coalesce.rb +1 -1
  36. data/lib/arel_extensions/nodes/collate.rb +1 -1
  37. data/lib/arel_extensions/nodes/concat.rb +6 -6
  38. data/lib/arel_extensions/nodes/date_diff.rb +40 -49
  39. data/lib/arel_extensions/nodes/duration.rb +2 -2
  40. data/lib/arel_extensions/nodes/format.rb +2 -2
  41. data/lib/arel_extensions/nodes/formatted_date.rb +2 -2
  42. data/lib/arel_extensions/nodes/formatted_number.rb +2 -2
  43. data/lib/arel_extensions/nodes/function.rb +6 -4
  44. data/lib/arel_extensions/nodes/is_null.rb +2 -0
  45. data/lib/arel_extensions/nodes/json.rb +27 -15
  46. data/lib/arel_extensions/nodes/levenshtein_distance.rb +2 -2
  47. data/lib/arel_extensions/nodes/locate.rb +1 -1
  48. data/lib/arel_extensions/nodes/power.rb +2 -2
  49. data/lib/arel_extensions/nodes/rand.rb +2 -2
  50. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  51. data/lib/arel_extensions/nodes/replace.rb +3 -3
  52. data/lib/arel_extensions/nodes/rollup.rb +4 -4
  53. data/lib/arel_extensions/nodes/round.rb +3 -3
  54. data/lib/arel_extensions/nodes/select.rb +1 -1
  55. data/lib/arel_extensions/nodes/std.rb +4 -4
  56. data/lib/arel_extensions/nodes/substring.rb +52 -2
  57. data/lib/arel_extensions/nodes/then.rb +1 -1
  58. data/lib/arel_extensions/nodes/trim.rb +2 -2
  59. data/lib/arel_extensions/nodes/union.rb +3 -3
  60. data/lib/arel_extensions/nodes/union_all.rb +3 -3
  61. data/lib/arel_extensions/nodes/wday.rb +2 -2
  62. data/lib/arel_extensions/null_functions.rb +5 -7
  63. data/lib/arel_extensions/predications.rb +22 -18
  64. data/lib/arel_extensions/string_functions.rb +26 -27
  65. data/lib/arel_extensions/version.rb +3 -1
  66. data/lib/arel_extensions/visitors/convert_format.rb +2 -2
  67. data/lib/arel_extensions/visitors/ibm_db.rb +5 -5
  68. data/lib/arel_extensions/visitors/mssql.rb +91 -92
  69. data/lib/arel_extensions/visitors/mysql.rb +89 -69
  70. data/lib/arel_extensions/visitors/oracle.rb +100 -104
  71. data/lib/arel_extensions/visitors/oracle12.rb +5 -6
  72. data/lib/arel_extensions/visitors/postgresql.rb +107 -94
  73. data/lib/arel_extensions/visitors/sqlite.rb +57 -65
  74. data/lib/arel_extensions/visitors/to_sql.rb +84 -74
  75. data/lib/arel_extensions/visitors.rb +6 -6
  76. data/lib/arel_extensions/warning.rb +5 -5
  77. data/lib/arel_extensions.rb +34 -27
  78. data/test/real_db_test.rb +31 -31
  79. data/test/visitors/test_to_sql.rb +2 -2
  80. data/test/with_ar/all_agnostic_test.rb +149 -15
  81. data/version_v1.rb +3 -1
  82. data/version_v2.rb +3 -1
  83. metadata +2 -30
@@ -20,23 +20,23 @@ module ArelExtensions
20
20
  'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', '
21
21
  }.freeze
22
22
 
23
- def visit_ArelExtensions_Nodes_ByteSize o, collector
23
+ def visit_ArelExtensions_Nodes_ByteSize(o, collector)
24
24
  collector << 'octet_length('
25
25
  collector = visit o.expr.coalesce(''), collector
26
26
  collector << ')'
27
27
  collector
28
28
  end
29
29
 
30
- def visit_ArelExtensions_Nodes_CharLength o, collector
30
+ def visit_ArelExtensions_Nodes_CharLength(o, collector)
31
31
  collector << 'length('
32
32
  collector = visit o.expr.coalesce(''), collector
33
33
  collector << ')'
34
34
  collector
35
35
  end
36
36
 
37
- def visit_ArelExtensions_Nodes_Rand o, collector
37
+ def visit_ArelExtensions_Nodes_Rand(o, collector)
38
38
  collector << 'RANDOM('
39
- if (o.left != nil && o.right != nil)
39
+ if !o.left.nil? && !o.right.nil?
40
40
  collector = visit o.left, collector
41
41
  collector << COMMA
42
42
  collector = isit o.right, collector
@@ -45,44 +45,41 @@ module ArelExtensions
45
45
  collector
46
46
  end
47
47
 
48
- def visit_ArelExtensions_Nodes_Power o, collector
48
+ def visit_ArelExtensions_Nodes_Power(o, collector)
49
49
  collector << 'POWER('
50
50
  o.expressions.each_with_index { |arg, i|
51
- collector << Arel::Visitors::ToSql::COMMA if i != 0
51
+ collector << COMMA if i != 0
52
52
  collector = visit arg, collector
53
53
  }
54
54
  collector << ')'
55
55
  collector
56
56
  end
57
57
 
58
- def visit_ArelExtensions_Nodes_Log10 o, collector
58
+ def visit_ArelExtensions_Nodes_Log10(o, collector)
59
59
  collector << 'LOG('
60
60
  o.expressions.each_with_index { |arg, i|
61
- collector << Arel::Visitors::ToSql::COMMA if i != 0
61
+ collector << COMMA if i != 0
62
62
  collector = visit arg, collector
63
63
  }
64
64
  collector << ')'
65
65
  collector
66
66
  end
67
67
 
68
-
69
68
  remove_method(:visit_Arel_Nodes_Regexp) rescue nil
70
- def visit_Arel_Nodes_Regexp o, collector
69
+ def visit_Arel_Nodes_Regexp(o, collector)
71
70
  collector = visit o.left, collector
72
71
  collector << ' ~ '
73
- collector = visit o.right, collector
74
- collector
72
+ visit o.right, collector
75
73
  end
76
74
 
77
75
  remove_method(:visit_Arel_Nodes_NotRegexp) rescue nil
78
- def visit_Arel_Nodes_NotRegexp o, collector
76
+ def visit_Arel_Nodes_NotRegexp(o, collector)
79
77
  collector = visit o.left, collector
80
78
  collector << ' !~ '
81
- collector = visit o.right, collector
82
- collector
79
+ visit o.right, collector
83
80
  end
84
81
 
85
- def visit_ArelExtensions_Nodes_Concat o, collector
82
+ def visit_ArelExtensions_Nodes_Concat(o, collector)
86
83
  collector << '('
87
84
  o.expressions.each_with_index { |arg, i|
88
85
  collector = visit arg, collector
@@ -92,8 +89,8 @@ module ArelExtensions
92
89
  collector
93
90
  end
94
91
 
95
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
96
- def visit_Arel_Nodes_As o, collector
92
+ alias old_visit_Arel_Nodes_As visit_Arel_Nodes_As rescue nil
93
+ def visit_Arel_Nodes_As(o, collector)
97
94
  if o.left.is_a?(Arel::Nodes::Binary)
98
95
  collector << '('
99
96
  collector = visit o.left, collector
@@ -113,7 +110,7 @@ module ArelExtensions
113
110
  collector
114
111
  end
115
112
 
116
- def visit_Aggregate_For_AggregateFunction o, collector
113
+ def visit_Aggregate_For_AggregateFunction(o, collector)
117
114
  if !o.order.blank? || !o.group.blank?
118
115
  collector << ' OVER ('
119
116
  if !o.group.blank?
@@ -135,7 +132,7 @@ module ArelExtensions
135
132
  collector
136
133
  end
137
134
 
138
- def visit_ArelExtensions_Nodes_GroupConcat o, collector
135
+ def visit_ArelExtensions_Nodes_GroupConcat(o, collector)
139
136
  collector << 'array_to_string(array_agg('
140
137
  collector = visit o.left, collector
141
138
  if o.order && !o.order.blank?
@@ -152,16 +149,16 @@ module ArelExtensions
152
149
  collector << COMMA
153
150
  sep = o.separator.is_a?(Arel::Nodes::Quoted) ? o.separator.expr : o.separator
154
151
  collector =
155
- if 'NULL' != sep
156
- visit o.separator, collector
157
- else
152
+ if 'NULL' == sep
158
153
  visit Arel.quoted(','), collector
154
+ else
155
+ visit o.separator, collector
159
156
  end
160
157
  collector << ')'
161
158
  collector
162
159
  end
163
160
 
164
- def visit_ArelExtensions_Nodes_Trim o, collector
161
+ def visit_ArelExtensions_Nodes_Trim(o, collector)
165
162
  collector << 'TRIM(BOTH '
166
163
  collector = visit o.right, collector
167
164
  collector << ' FROM '
@@ -170,7 +167,7 @@ module ArelExtensions
170
167
  collector
171
168
  end
172
169
 
173
- def visit_ArelExtensions_Nodes_Ltrim o, collector
170
+ def visit_ArelExtensions_Nodes_Ltrim(o, collector)
174
171
  collector << 'TRIM(LEADING '
175
172
  collector = visit o.right, collector
176
173
  collector << ' FROM '
@@ -179,7 +176,7 @@ module ArelExtensions
179
176
  collector
180
177
  end
181
178
 
182
- def visit_ArelExtensions_Nodes_Rtrim o, collector
179
+ def visit_ArelExtensions_Nodes_Rtrim(o, collector)
183
180
  collector << 'TRIM(TRAILING '
184
181
  collector = visit o.right, collector
185
182
  collector << ' FROM '
@@ -188,12 +185,12 @@ module ArelExtensions
188
185
  collector
189
186
  end
190
187
 
191
- def visit_ArelExtensions_Nodes_Format o, collector
188
+ def visit_ArelExtensions_Nodes_Format(o, collector)
192
189
  visit_ArelExtensions_Nodes_FormattedDate o, collector
193
190
  end
194
191
 
195
- def visit_ArelExtensions_Nodes_FormattedDate o, collector
196
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
192
+ def visit_ArelExtensions_Nodes_FormattedDate(o, collector)
193
+ fmt = ArelExtensions::Visitors.strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
197
194
  collector << 'TO_CHAR('
198
195
  collector << '(' if o.time_zone
199
196
  collector = visit o.left, collector
@@ -214,17 +211,17 @@ module ArelExtensions
214
211
  collector
215
212
  end
216
213
 
217
- def visit_ArelExtensions_Nodes_Repeat o, collector
214
+ def visit_ArelExtensions_Nodes_Repeat(o, collector)
218
215
  collector << 'REPEAT('
219
216
  o.expressions.each_with_index { |arg, i|
220
- collector << Arel::Visitors::ToSql::COMMA if i != 0
217
+ collector << COMMA if i != 0
221
218
  collector = visit arg, collector
222
219
  }
223
220
  collector << ')'
224
221
  collector
225
222
  end
226
223
 
227
- def visit_ArelExtensions_Nodes_AiMatches o, collector
224
+ def visit_ArelExtensions_Nodes_AiMatches(o, collector)
228
225
  collector = visit o.left.ai_collate, collector
229
226
  collector << ' LIKE '
230
227
  collector = visit o.right.ai_collate, collector
@@ -236,7 +233,7 @@ module ArelExtensions
236
233
  end
237
234
  end
238
235
 
239
- def visit_ArelExtensions_Nodes_AiIMatches o, collector
236
+ def visit_ArelExtensions_Nodes_AiIMatches(o, collector)
240
237
  collector = visit o.left.ai_collate, collector
241
238
  collector << ' ILIKE '
242
239
  collector = visit o.right.ai_collate, collector
@@ -248,7 +245,7 @@ module ArelExtensions
248
245
  end
249
246
  end
250
247
 
251
- def visit_ArelExtensions_Nodes_SMatches o, collector
248
+ def visit_ArelExtensions_Nodes_SMatches(o, collector)
252
249
  collector = visit o.left, collector
253
250
  collector << ' LIKE '
254
251
  collector = visit o.right, collector
@@ -260,7 +257,7 @@ module ArelExtensions
260
257
  end
261
258
  end
262
259
 
263
- def visit_ArelExtensions_Nodes_Collate o, collector
260
+ def visit_ArelExtensions_Nodes_Collate(o, collector)
264
261
  if o.ai
265
262
  collector << 'unaccent('
266
263
  collector = visit o.expressions.first, collector
@@ -273,20 +270,19 @@ module ArelExtensions
273
270
  collector
274
271
  end
275
272
 
276
- def visit_ArelExtensions_Nodes_DateAdd o, collector
273
+ def visit_ArelExtensions_Nodes_DateAdd(o, collector)
277
274
  collector = visit o.left, collector
278
275
  collector << ' + ' # (o.right.value >= 0 ? ' + ' : ' - ')
279
- collector = visit o.postgresql_value(o.right), collector
280
- collector
276
+ visit o.postgresql_value(o.right), collector
281
277
  end
282
278
 
283
- def visit_ArelExtensions_Nodes_DateDiff o, collector
284
- 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
285
- collector << if o.left_node_type == :ruby_time || o.left_node_type == :datetime || o.left_node_type == :time
279
+ def visit_ArelExtensions_Nodes_DateDiff(o, collector)
280
+ if %i[ruby_date ruby_time date datetime time].include?(o.right_node_type)
281
+ collector << if %i[ruby_time datetime time].include?(o.left_node_type)
286
282
  "DATEDIFF('second', "
287
- else
288
- "DATEDIFF('day', "
289
- end
283
+ else
284
+ "DATEDIFF('day', "
285
+ end
290
286
  collector = visit o.right, collector
291
287
  collector << (o.right_node_type == :date ? '::date' : '::timestamp')
292
288
  collector << COMMA
@@ -306,10 +302,11 @@ module ArelExtensions
306
302
  collector
307
303
  end
308
304
 
309
- def visit_ArelExtensions_Nodes_Duration o, collector
305
+ def visit_ArelExtensions_Nodes_Duration(o, collector)
310
306
  if o.with_interval
311
- interval = case o.left
312
- when 'd', 'm', 'y'
307
+ interval =
308
+ case o.left
309
+ when 'd', 'm', 'y'
313
310
  'DAY'
314
311
  when 'h', 'mn', 's'
315
312
  'SECOND'
@@ -328,7 +325,7 @@ module ArelExtensions
328
325
  collector
329
326
  end
330
327
 
331
- def visit_ArelExtensions_Nodes_Locate o, collector
328
+ def visit_ArelExtensions_Nodes_Locate(o, collector)
332
329
  collector << 'POSITION('
333
330
  collector = visit o.right, collector
334
331
  collector << ' IN '
@@ -337,7 +334,9 @@ module ArelExtensions
337
334
  collector
338
335
  end
339
336
 
340
- def visit_ArelExtensions_Nodes_Substring o, collector
337
+ def visit_ArelExtensions_Nodes_Substring(o, collector)
338
+ return visit(o.range_substring_node, collector) if o.range?
339
+
341
340
  collector << 'SUBSTR('
342
341
  o.expressions.each_with_index { |arg, i|
343
342
  collector << COMMA if i != 0
@@ -347,35 +346,35 @@ module ArelExtensions
347
346
  collector
348
347
  end
349
348
 
350
- def visit_ArelExtensions_Nodes_RegexpReplace o, collector
349
+ def visit_ArelExtensions_Nodes_RegexpReplace(o, collector)
351
350
  collector << 'REGEXP_REPLACE('
352
351
  visit o.left, collector
353
- collector << Arel::Visitors::ToSql::COMMA
352
+ collector << COMMA
354
353
  tab = o.pattern.inspect + 'g' # Make it always global
355
354
  pattern = tab.split('/')[1..-2].join('/')
356
355
  flags = tab.split('/')[-1]
357
356
  visit Arel.quoted(pattern), collector
358
- collector << Arel::Visitors::ToSql::COMMA
357
+ collector << COMMA
359
358
  visit o.substitute, collector
360
- collector << Arel::Visitors::ToSql::COMMA
359
+ collector << COMMA
361
360
  visit Arel.quoted(flags + 'g'), collector
362
361
  collector << ')'
363
362
  collector
364
363
  end
365
364
 
366
- def visit_ArelExtensions_Nodes_IsNull o, collector
365
+ def visit_ArelExtensions_Nodes_IsNull(o, collector)
367
366
  collector = visit o.expr, collector
368
367
  collector << ' IS NULL'
369
368
  collector
370
369
  end
371
370
 
372
- def visit_ArelExtensions_Nodes_IsNotNull o, collector
371
+ def visit_ArelExtensions_Nodes_IsNotNull(o, collector)
373
372
  collector = visit o.expr, collector
374
- collector << ' IS NOT NULL'
375
- collector
373
+ collector << ' IS NOT NULL'
374
+ collector
376
375
  end
377
376
 
378
- def visit_ArelExtensions_Nodes_Sum o, collector
377
+ def visit_ArelExtensions_Nodes_Sum(o, collector)
379
378
  collector << 'sum('
380
379
  collector = visit o.expr, collector
381
380
  collector << ')'
@@ -383,14 +382,14 @@ module ArelExtensions
383
382
  collector
384
383
  end
385
384
 
386
- def visit_ArelExtensions_Nodes_Wday o, collector
385
+ def visit_ArelExtensions_Nodes_Wday(o, collector)
387
386
  collector << 'EXRTACT(DOW, '
388
387
  collector = visit o.date, collector
389
388
  collector << ')'
390
389
  collector
391
390
  end
392
391
 
393
- def visit_ArelExtensions_Nodes_Cast o, collector
392
+ def visit_ArelExtensions_Nodes_Cast(o, collector)
394
393
  as_attr =
395
394
  case o.as_attr
396
395
  when :string
@@ -426,11 +425,11 @@ module ArelExtensions
426
425
  collector
427
426
  end
428
427
 
429
- def visit_ArelExtensions_Nodes_FormattedNumber o, collector
428
+ def visit_ArelExtensions_Nodes_FormattedNumber(o, collector)
430
429
  col = o.left.coalesce(0)
431
430
  comma = o.precision == 0 ? '' : (NUMBER_COMMA_MAPPING[o.locale][0] || '.')
432
431
  thousand_separator = NUMBER_COMMA_MAPPING[o.locale][1] || (NUMBER_COMMA_MAPPING[o.locale] ? '' : 'G')
433
- nines_after = (1..o.precision).map{'9'}.join('')
432
+ nines_after = (1..o.precision).map { '9' }.join('')
434
433
  nines_before = ("999#{thousand_separator}" * 4 + '990')
435
434
 
436
435
  sign = Arel.when(col < 0).
@@ -487,10 +486,8 @@ module ArelExtensions
487
486
  collector
488
487
  end
489
488
 
490
-
491
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
492
- def visit_Arel_Nodes_SelectStatement o, collector
493
-
489
+ alias old_visit_Arel_Nodes_SelectStatement visit_Arel_Nodes_SelectStatement rescue nil
490
+ def visit_Arel_Nodes_SelectStatement(o, collector)
494
491
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
495
492
  o = o.dup
496
493
  o.orders = []
@@ -498,16 +495,16 @@ module ArelExtensions
498
495
  old_visit_Arel_Nodes_SelectStatement(o, collector)
499
496
  end
500
497
 
501
- alias_method(:old_visit_Arel_Nodes_TableAlias, :visit_Arel_Nodes_TableAlias) rescue nil
502
- def visit_Arel_Nodes_TableAlias o, collector
498
+ alias old_visit_Arel_Nodes_TableAlias visit_Arel_Nodes_TableAlias rescue nil
499
+ def visit_Arel_Nodes_TableAlias(o, collector)
503
500
  if o.name.length > 63
504
501
  o = Arel::Table.new(o.table_name).alias(Arel.shorten(o.name))
505
502
  end
506
503
  old_visit_Arel_Nodes_TableAlias(o, collector)
507
504
  end
508
505
 
509
- alias_method(:old_visit_Arel_Attributes_Attribute, :visit_Arel_Attributes_Attribute) rescue nil
510
- def visit_Arel_Attributes_Attribute o, collector
506
+ alias old_visit_Arel_Attributes_Attribute visit_Arel_Attributes_Attribute rescue nil
507
+ def visit_Arel_Attributes_Attribute(o, collector)
511
508
  join_name = o.relation.table_alias || o.relation.name
512
509
  if join_name.length > 63
513
510
  join_name = Arel.shorten(join_name)
@@ -515,7 +512,7 @@ module ArelExtensions
515
512
  collector << "#{quote_table_name join_name}.#{quote_column_name o.name}"
516
513
  end
517
514
 
518
- def visit_ArelExtensions_Nodes_Std o, collector
515
+ def visit_ArelExtensions_Nodes_Std(o, collector)
519
516
  collector << (o.unbiased_estimator ? 'STDDEV_SAMP(' : 'STDDEV_POP(')
520
517
  visit o.left, collector
521
518
  collector << ')'
@@ -523,7 +520,7 @@ module ArelExtensions
523
520
  collector
524
521
  end
525
522
 
526
- def visit_ArelExtensions_Nodes_Variance o, collector
523
+ def visit_ArelExtensions_Nodes_Variance(o, collector)
527
524
  collector << (o.unbiased_estimator ? 'VAR_SAMP(' : 'VAR_POP(')
528
525
  visit o.left, collector
529
526
  collector << ')'
@@ -531,25 +528,31 @@ module ArelExtensions
531
528
  collector
532
529
  end
533
530
 
534
- def visit_ArelExtensions_Nodes_Json o, collector
531
+ def visit_ArelExtensions_Nodes_Json(o, collector)
535
532
  case o.dict
536
533
  when Array
537
- collector << 'to_jsonb(array['
538
- o.dict.each.with_index do |v, i|
539
- if i != 0
540
- collector << Arel::Visitors::MySQL::COMMA
534
+ if o.dict.empty?
535
+ # `to_jsonb(array[])` would raise "cannot determine type of empty array";
536
+ # an empty array is simply the `[]` JSON literal.
537
+ collector << %('[]'::jsonb)
538
+ else
539
+ collector << 'to_jsonb(array['
540
+ o.dict.each.with_index do |v, i|
541
+ if i != 0
542
+ collector << COMMA
543
+ end
544
+ collector = visit v, collector
541
545
  end
542
- collector = visit v, collector
546
+ collector << '])'
543
547
  end
544
- collector << '])'
545
548
  when Hash
546
549
  collector << 'jsonb_build_object('
547
550
  o.dict.each.with_index do |(k, v), i|
548
551
  if i != 0
549
- collector << Arel::Visitors::MySQL::COMMA
552
+ collector << COMMA
550
553
  end
551
554
  collector = visit k, collector
552
- collector << Arel::Visitors::MySQL::COMMA
555
+ collector << COMMA
553
556
  collector = visit v, collector
554
557
  end
555
558
  collector << ')'
@@ -557,15 +560,24 @@ module ArelExtensions
557
560
  collector = visit Arel.quoted("#{o.dict}"), collector
558
561
  collector << '::jsonb'
559
562
  when NilClass
560
- collector << %Q['null'::jsonb]
563
+ collector << %('null'::jsonb)
561
564
  else
562
- collector = visit o.dict, collector
563
- collector << '::jsonb'
565
+ if o.dict.is_a?(Arel::Nodes::Quoted) && o.dict.expr.nil?
566
+ # `Arel.null` must mean the JSON null member, not SQL NULL:
567
+ # `to_jsonb(NULL)` would raise a polymorphic-type error.
568
+ collector << %('null'::jsonb)
569
+ else
570
+ # `to_jsonb` rather than `::jsonb` so a non-JSON value (e.g. a text column) is
571
+ # encoded as a JSON string instead of rejected by the server.
572
+ collector << 'to_jsonb('
573
+ collector = visit o.dict, collector
574
+ collector << ')'
575
+ end
564
576
  end
565
577
  collector
566
578
  end
567
579
 
568
- def visit_ArelExtensions_Nodes_JsonMerge o, collector
580
+ def visit_ArelExtensions_Nodes_JsonMerge(o, collector)
569
581
  o.expressions.each.with_index do |v, i|
570
582
  if i != 0
571
583
  collector << ' || '
@@ -575,28 +587,29 @@ module ArelExtensions
575
587
  collector
576
588
  end
577
589
 
578
- def visit_ArelExtensions_Nodes_JsonGet o, collector
590
+ def visit_ArelExtensions_Nodes_JsonGet(o, collector)
579
591
  collector = visit o.dict, collector
580
592
  collector << ' ->> '
581
- collector = visit o.key, collector
582
- collector
593
+ visit o.key, collector
583
594
  end
584
595
 
585
- def visit_ArelExtensions_Nodes_JsonSet o, collector
596
+ def visit_ArelExtensions_Nodes_JsonSet(o, collector)
586
597
  collector << 'jsonb_set('
587
598
  collector = visit o.dict, collector
588
- collector << Arel::Visitors::MySQL::COMMA
599
+ collector << COMMA
589
600
  collector << 'array['
590
601
  collector = visit o.key, collector
591
602
  collector << ']'
592
- collector << Arel::Visitors::MySQL::COMMA
603
+ collector << COMMA
604
+ collector << 'COALESCE('
593
605
  collector = visit o.value, collector
594
- collector << Arel::Visitors::MySQL::COMMA
606
+ collector << ", 'null'::jsonb)"
607
+ collector << COMMA
595
608
  collector << 'true)'
596
609
  collector
597
610
  end
598
611
 
599
- def visit_ArelExtensions_Nodes_JsonGroup o, collector
612
+ def visit_ArelExtensions_Nodes_JsonGroup(o, collector)
600
613
  if o.as_array
601
614
  collector << 'jsonb_agg('
602
615
  collector = visit o.dict, collector
@@ -610,7 +623,7 @@ module ArelExtensions
610
623
  end
611
624
  collector << 'jsonb_object_agg('
612
625
  collector = visit k, collector
613
- collector << Arel::Visitors::MySQL::COMMA
626
+ collector << COMMA
614
627
  collector = visit v, collector
615
628
  collector << ')'
616
629
  end