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