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
@@ -25,7 +25,7 @@ module ArelExtensions
25
25
  end
26
26
 
27
27
  if private_method_defined?(:visit_Arel_Nodes_SelectCore) || method_defined?(:visit_Arel_Nodes_SelectCore)
28
- alias_method(:old_visit_Arel_Nodes_SelectCore, :visit_Arel_Nodes_SelectCore)
28
+ alias old_visit_Arel_Nodes_SelectCore visit_Arel_Nodes_SelectCore
29
29
  end
30
30
  # The whole purpose of this override is to fix the behavior of RollUp.
31
31
  # All other databases treat RollUp sanely, execpt MySQL which requires
@@ -33,7 +33,7 @@ module ArelExtensions
33
33
  def visit_Arel_Nodes_SelectCore(o, collector)
34
34
  collector << 'SELECT'
35
35
 
36
- collector = collect_optimizer_hints(o, collector) if self.respond_to?(:collect_optimizer_hinsts)
36
+ collector = collect_optimizer_hints(o, collector) if respond_to?(:collect_optimizer_hints, true)
37
37
  collector = maybe_visit o.set_quantifier, collector
38
38
 
39
39
  collect_nodes_for o.projections, collector, ' '
@@ -65,20 +65,20 @@ module ArelExtensions
65
65
  end
66
66
 
67
67
  # Math functions
68
- def visit_ArelExtensions_Nodes_Log10 o, collector
68
+ def visit_ArelExtensions_Nodes_Log10(o, collector)
69
69
  collector << 'LOG10('
70
70
  o.expressions.each_with_index { |arg, i|
71
- collector << Arel::Visitors::ToSql::COMMA if i != 0
71
+ collector << COMMA if i != 0
72
72
  collector = visit arg, collector
73
73
  }
74
74
  collector << ')'
75
75
  collector
76
76
  end
77
77
 
78
- def visit_ArelExtensions_Nodes_Power o, collector
78
+ def visit_ArelExtensions_Nodes_Power(o, collector)
79
79
  collector << 'POW('
80
80
  o.expressions.each_with_index { |arg, i|
81
- collector << Arel::Visitors::ToSql::COMMA if i != 0
81
+ collector << COMMA if i != 0
82
82
  collector = visit arg, collector
83
83
  }
84
84
  collector << ')'
@@ -86,7 +86,21 @@ module ArelExtensions
86
86
  end
87
87
 
88
88
  # String functions
89
- def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
89
+ def visit_ArelExtensions_Nodes_ByteSize(o, collector)
90
+ collector << 'LENGTH('
91
+ collector = visit o.expr.coalesce(''), collector
92
+ collector << ')'
93
+ collector
94
+ end
95
+
96
+ def visit_ArelExtensions_Nodes_CharLength(o, collector)
97
+ collector << 'CHAR_LENGTH('
98
+ collector = visit o.expr.coalesce(''), collector
99
+ collector << ')'
100
+ collector
101
+ end
102
+
103
+ def visit_ArelExtensions_Nodes_IMatches(o, collector) # insensitive on ASCII
90
104
  collector << 'LOWER('
91
105
  collector = visit o.left, collector
92
106
  collector << ') LIKE LOWER('
@@ -99,7 +113,7 @@ module ArelExtensions
99
113
  collector
100
114
  end
101
115
 
102
- def visit_ArelExtensions_Nodes_AiMatches o, collector
116
+ def visit_ArelExtensions_Nodes_AiMatches(o, collector)
103
117
  collector = visit o.left.ai_collate, collector
104
118
  collector << ' LIKE '
105
119
  collector = visit o.right.ai_collate, collector
@@ -110,7 +124,7 @@ module ArelExtensions
110
124
  collector
111
125
  end
112
126
 
113
- def visit_ArelExtensions_Nodes_AiIMatches o, collector
127
+ def visit_ArelExtensions_Nodes_AiIMatches(o, collector)
114
128
  collector = visit o.left.ai_collate, collector
115
129
  collector << ' LIKE '
116
130
  collector = visit o.right.ai_collate, collector
@@ -121,7 +135,7 @@ module ArelExtensions
121
135
  collector
122
136
  end
123
137
 
124
- def visit_ArelExtensions_Nodes_SMatches o, collector
138
+ def visit_ArelExtensions_Nodes_SMatches(o, collector)
125
139
  collector = visit o.left.collate, collector
126
140
  collector << ' LIKE '
127
141
  collector = visit o.right.collate, collector
@@ -132,7 +146,7 @@ module ArelExtensions
132
146
  collector
133
147
  end
134
148
 
135
- def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
149
+ def visit_ArelExtensions_Nodes_IDoesNotMatch(o, collector)
136
150
  collector << 'LOWER('
137
151
  collector = visit o.left, collector
138
152
  collector << ') NOT LIKE LOWER('
@@ -145,7 +159,7 @@ module ArelExtensions
145
159
  collector
146
160
  end
147
161
 
148
- def visit_ArelExtensions_Nodes_Collate o, collector
162
+ def visit_ArelExtensions_Nodes_Collate(o, collector)
149
163
  charset =
150
164
  case o.expressions.first
151
165
  when Arel::Attributes::Attribute
@@ -156,7 +170,7 @@ module ArelExtensions
156
170
  Arel::Table.engine.connection.charset || 'utf8'
157
171
  end
158
172
  else
159
- (o.option == 'latin1') ? 'latin1' : 'utf8'
173
+ o.option == 'latin1' ? 'latin1' : 'utf8'
160
174
  end
161
175
  collector = visit o.expressions.first, collector
162
176
  collector <<
@@ -171,7 +185,7 @@ module ArelExtensions
171
185
  collector
172
186
  end
173
187
 
174
- def visit_ArelExtensions_Nodes_Concat o, collector
188
+ def visit_ArelExtensions_Nodes_Concat(o, collector)
175
189
  collector << 'CONCAT('
176
190
  o.expressions.each_with_index { |arg, i|
177
191
  collector << COMMA if i != 0
@@ -189,16 +203,16 @@ module ArelExtensions
189
203
 
190
204
  def visit_Arel_Nodes_RollUp(o, collector)
191
205
  visit o.expr, collector
192
- collector << " WITH ROLLUP"
206
+ collector << ' WITH ROLLUP'
193
207
  end
194
208
 
195
- def visit_ArelExtensions_Nodes_GroupConcat o, collector
209
+ def visit_ArelExtensions_Nodes_GroupConcat(o, collector)
196
210
  collector << 'GROUP_CONCAT('
197
211
  collector = visit o.left, collector
198
212
  if !o.order.blank?
199
213
  collector << ' ORDER BY '
200
214
  o.order.each_with_index do |order, i|
201
- collector << Arel::Visitors::ToSql::COMMA if i != 0
215
+ collector << COMMA if i != 0
202
216
  collector = visit order, collector
203
217
  end
204
218
  end
@@ -211,7 +225,7 @@ module ArelExtensions
211
225
  collector
212
226
  end
213
227
 
214
- def visit_ArelExtensions_Nodes_Trim o, collector
228
+ def visit_ArelExtensions_Nodes_Trim(o, collector)
215
229
  collector << 'TRIM(' # BOTH
216
230
  collector = visit o.right, collector
217
231
  collector << ' FROM '
@@ -220,7 +234,7 @@ module ArelExtensions
220
234
  collector
221
235
  end
222
236
 
223
- def visit_ArelExtensions_Nodes_Ltrim o, collector
237
+ def visit_ArelExtensions_Nodes_Ltrim(o, collector)
224
238
  collector << 'TRIM(LEADING '
225
239
  collector = visit o.right, collector
226
240
  collector << ' FROM '
@@ -229,7 +243,7 @@ module ArelExtensions
229
243
  collector
230
244
  end
231
245
 
232
- def visit_ArelExtensions_Nodes_Rtrim o, collector
246
+ def visit_ArelExtensions_Nodes_Rtrim(o, collector)
233
247
  collector << 'TRIM(TRAILING '
234
248
  collector = visit o.right, collector
235
249
  collector << ' FROM '
@@ -238,24 +252,24 @@ module ArelExtensions
238
252
  collector
239
253
  end
240
254
 
241
- def visit_ArelExtensions_Nodes_Repeat o, collector
255
+ def visit_ArelExtensions_Nodes_Repeat(o, collector)
242
256
  collector << 'REPEAT('
243
257
  o.expressions.each_with_index { |arg, i|
244
- collector << Arel::Visitors::ToSql::COMMA if i != 0
258
+ collector << COMMA if i != 0
245
259
  collector = visit arg, collector
246
260
  }
247
261
  collector << ')'
248
262
  collector
249
263
  end
250
264
 
251
- def visit_ArelExtensions_Nodes_RegexpReplace o, collector
265
+ def visit_ArelExtensions_Nodes_RegexpReplace(o, collector)
252
266
  if !regexp_replace_supported?
253
267
  warn('Warning: ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash')
254
268
  end
255
- super(o, collector)
269
+ super
256
270
  end
257
271
 
258
- def visit_ArelExtensions_Nodes_Format o, collector
272
+ def visit_ArelExtensions_Nodes_Format(o, collector)
259
273
  # One use case we met is
260
274
  # `case…when…then(valid_date).else(Arel.null).format(…)`.
261
275
  #
@@ -264,10 +278,12 @@ module ArelExtensions
264
278
  # infer the proper type.
265
279
  first = o.expressions[0]
266
280
  type =
267
- o.col_type.nil? \
268
- && (first.respond_to?(:return_type) && !first&.return_type.nil?) \
269
- ? first&.return_type \
270
- : o.col_type
281
+ if o.col_type.nil? \
282
+ && first.respond_to?(:return_type) && !first&.return_type.nil?
283
+ first&.return_type
284
+ else
285
+ o.col_type
286
+ end
271
287
 
272
288
  case type
273
289
  when :date, :datetime, :time
@@ -275,9 +291,9 @@ module ArelExtensions
275
291
  when :integer, :float, :decimal
276
292
  collector << 'FORMAT('
277
293
  collector = visit o.left, collector
278
- collector << Arel::Visitors::ToSql::COMMA
294
+ collector << COMMA
279
295
  collector << '2'
280
- collector << Arel::Visitors::ToSql::COMMA
296
+ collector << COMMA
281
297
  collector = visit o.right, collector
282
298
  collector << ')'
283
299
  else
@@ -286,8 +302,8 @@ module ArelExtensions
286
302
  collector
287
303
  end
288
304
 
289
- def visit_ArelExtensions_Nodes_FormattedDate o, collector
290
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
305
+ def visit_ArelExtensions_Nodes_FormattedDate(o, collector)
306
+ fmt = ArelExtensions::Visitors.strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
291
307
  collector << 'DATE_FORMAT('
292
308
  collector << 'CONVERT_TZ(' if o.time_zone
293
309
  collector = visit o.left, collector
@@ -309,7 +325,7 @@ module ArelExtensions
309
325
  collector << ')'
310
326
  end
311
327
 
312
- def visit_ArelExtensions_Nodes_DateDiff o, collector
328
+ def visit_ArelExtensions_Nodes_DateDiff(o, collector)
313
329
  case o.right_node_type
314
330
  when :ruby_date, :ruby_time, :date, :datetime, :time
315
331
  collector <<
@@ -339,7 +355,7 @@ module ArelExtensions
339
355
  collector
340
356
  end
341
357
 
342
- def visit_ArelExtensions_Nodes_DateAdd o, collector
358
+ def visit_ArelExtensions_Nodes_DateAdd(o, collector)
343
359
  collector << 'DATE_ADD('
344
360
  collector = visit o.left, collector
345
361
  collector << COMMA
@@ -348,7 +364,7 @@ module ArelExtensions
348
364
  collector
349
365
  end
350
366
 
351
- def visit_ArelExtensions_Nodes_Duration o, collector
367
+ def visit_ArelExtensions_Nodes_Duration(o, collector)
352
368
  if o.left == 'wd'
353
369
  collector << '(WEEKDAY('
354
370
  collector = visit o.right, collector
@@ -374,28 +390,28 @@ module ArelExtensions
374
390
  collector
375
391
  end
376
392
 
377
- def visit_ArelExtensions_Nodes_IsNull o, collector
393
+ def visit_ArelExtensions_Nodes_IsNull(o, collector)
378
394
  collector << 'ISNULL('
379
395
  collector = visit o.expr, collector
380
396
  collector << ')'
381
397
  collector
382
398
  end
383
399
 
384
- def visit_ArelExtensions_Nodes_IsNotNull o, collector
400
+ def visit_ArelExtensions_Nodes_IsNotNull(o, collector)
385
401
  collector << 'NOT ISNULL('
386
- collector = visit o.expr, collector
387
- collector << ')'
388
- collector
402
+ collector = visit o.expr, collector
403
+ collector << ')'
404
+ collector
389
405
  end
390
406
 
391
- def visit_ArelExtensions_Nodes_Wday o, collector
407
+ def visit_ArelExtensions_Nodes_Wday(o, collector)
392
408
  collector << '(WEEKDAY('
393
409
  collector = visit o.date, collector
394
410
  collector << ') + 1) % 7'
395
411
  collector
396
412
  end
397
413
 
398
- def visit_ArelExtensions_Nodes_Cast o, collector
414
+ def visit_ArelExtensions_Nodes_Cast(o, collector)
399
415
  as_attr =
400
416
  case o.as_attr
401
417
  when :binary then 'binary'
@@ -416,8 +432,8 @@ module ArelExtensions
416
432
  collector
417
433
  end
418
434
 
419
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
420
- def visit_Arel_Nodes_SelectStatement o, collector
435
+ alias old_visit_Arel_Nodes_SelectStatement visit_Arel_Nodes_SelectStatement rescue nil
436
+ def visit_Arel_Nodes_SelectStatement(o, collector)
421
437
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
422
438
  o = o.dup
423
439
  o.orders = []
@@ -425,8 +441,8 @@ module ArelExtensions
425
441
  old_visit_Arel_Nodes_SelectStatement(o, collector)
426
442
  end
427
443
 
428
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
429
- def visit_Arel_Nodes_As o, collector
444
+ alias old_visit_Arel_Nodes_As visit_Arel_Nodes_As rescue nil
445
+ def visit_Arel_Nodes_As(o, collector)
430
446
  if o.left.is_a?(Arel::Nodes::Binary)
431
447
  collector << '('
432
448
  collector = visit o.left, collector
@@ -446,7 +462,7 @@ module ArelExtensions
446
462
  collector
447
463
  end
448
464
 
449
- def visit_ArelExtensions_Nodes_FormattedNumber o, collector
465
+ def visit_ArelExtensions_Nodes_FormattedNumber(o, collector)
450
466
  col = o.left.coalesce(0)
451
467
  params = o.locale ? [o.precision, Arel.quoted(o.locale)] : [o.precision]
452
468
  sign = Arel.when(col < 0).
@@ -496,7 +512,7 @@ module ArelExtensions
496
512
  collector
497
513
  end
498
514
 
499
- def visit_Aggregate_For_AggregateFunction o, collector
515
+ def visit_Aggregate_For_AggregateFunction(o, collector)
500
516
  if !window_supported?
501
517
  warn('Warning: ArelExtensions: Window Functions are not available in the current version of the DBMS.')
502
518
  return collector
@@ -519,7 +535,7 @@ module ArelExtensions
519
535
  collector
520
536
  end
521
537
 
522
- def visit_ArelExtensions_Nodes_Std o, collector
538
+ def visit_ArelExtensions_Nodes_Std(o, collector)
523
539
  collector << (o.unbiased_estimator ? 'STDDEV_SAMP(' : 'STDDEV_POP(')
524
540
  visit o.left, collector
525
541
  collector << ')'
@@ -527,7 +543,7 @@ module ArelExtensions
527
543
  collector
528
544
  end
529
545
 
530
- def visit_ArelExtensions_Nodes_Variance o, collector
546
+ def visit_ArelExtensions_Nodes_Variance(o, collector)
531
547
  collector << (o.unbiased_estimator ? 'VAR_SAMP(' : 'VAR_POP(')
532
548
  visit o.left, collector
533
549
  collector << ')'
@@ -550,19 +566,19 @@ module ArelExtensions
550
566
 
551
567
  def version_supported?(mariadb_v = '10.2.3', mysql_v = '5.7.0')
552
568
  conn = Arel::Table.engine.connection
553
- conn.send(:mariadb?) && \
554
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v || \
555
- conn.respond_to?(:version) && conn.send(:version) >= mariadb_v || \
556
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mariadb_v) || \
557
- !conn.send(:mariadb?) && \
558
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v || \
559
- conn.respond_to?(:version) && conn.send(:version) >= mysql_v || \
560
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mysql_v)
569
+ conn.send(:mariadb?) &&
570
+ (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v ||
571
+ conn.respond_to?(:version) && conn.send(:version) >= mariadb_v ||
572
+ conn.instance_variable_get(:@version) && conn.instance_variable_get(:@version) >= mariadb_v) ||
573
+ !conn.send(:mariadb?) &&
574
+ (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v ||
575
+ conn.respond_to?(:version) && conn.send(:version) >= mysql_v ||
576
+ conn.instance_variable_get(:@version) && conn.instance_variable_get(:@version) >= mysql_v)
561
577
  # ideally we should parse the instance_variable @full_version because @version contains only the supposedly
562
578
  # corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
563
579
  end
564
580
 
565
- def visit_ArelExtensions_Nodes_Json o, collector
581
+ def visit_ArelExtensions_Nodes_Json(o, collector)
566
582
  return super if !json_supported?
567
583
 
568
584
  case o.dict
@@ -572,7 +588,7 @@ module ArelExtensions
572
588
  if i != 0
573
589
  collector << COMMA
574
590
  end
575
- collector = visit v, collector
591
+ collector = visit_json_value(o, v, collector)
576
592
  end
577
593
  collector << ')'
578
594
  when Hash
@@ -583,16 +599,34 @@ module ArelExtensions
583
599
  end
584
600
  collector = visit k, collector
585
601
  collector << COMMA
586
- collector = visit v, collector
602
+ collector = visit_json_value(o, v, collector)
587
603
  end
588
604
  collector << ')'
589
605
  else
590
- collector = visit o.dict, collector
606
+ collector = visit_json_value(o, o.dict, collector)
607
+ end
608
+ collector
609
+ end
610
+
611
+ # A JSON Boolean must render as `true`/`false`, not the integer `1`/`0` that MySQL
612
+ # collapses `TRUE`/`FALSE` into inside JSON functions (MariaDB keeps them boolean).
613
+ def visit_json_value(o, v, collector)
614
+ if o.boolean_literal?(v)
615
+ value = v.is_a?(Arel::Nodes::Quoted) ? v.expr : v
616
+ collector << "JSON_EXTRACT('#{value}', '$')"
617
+ elsif o.type_of_node(v) == :boolean
618
+ collector << 'JSON_EXTRACT(CASE WHEN '
619
+ collector = visit v, collector
620
+ collector << " IS NULL THEN NULL WHEN "
621
+ collector = visit v, collector
622
+ collector << " THEN 'true' ELSE 'false' END, '$')"
623
+ else
624
+ collector = visit v, collector
591
625
  end
592
626
  collector
593
627
  end
594
628
 
595
- def visit_ArelExtensions_Nodes_JsonMerge o, collector
629
+ def visit_ArelExtensions_Nodes_JsonMerge(o, collector)
596
630
  collector << 'JSON_MERGE_PATCH('
597
631
  o.expressions.each.with_index do |v, i|
598
632
  if i != 0
@@ -604,7 +638,7 @@ module ArelExtensions
604
638
  collector
605
639
  end
606
640
 
607
- def visit_ArelExtensions_Nodes_JsonGet o, collector
641
+ def visit_ArelExtensions_Nodes_JsonGet(o, collector)
608
642
  collector << 'JSON_EXTRACT('
609
643
  collector = visit o.dict, collector
610
644
  collector << COMMA
@@ -617,7 +651,7 @@ module ArelExtensions
617
651
  collector
618
652
  end
619
653
 
620
- def visit_ArelExtensions_Nodes_JsonSet o, collector
654
+ def visit_ArelExtensions_Nodes_JsonSet(o, collector)
621
655
  collector << 'JSON_SET('
622
656
  collector = visit o.dict, collector
623
657
  collector << COMMA
@@ -632,7 +666,7 @@ module ArelExtensions
632
666
  collector
633
667
  end
634
668
 
635
- def visit_ArelExtensions_Nodes_JsonGroup o, collector
669
+ def visit_ArelExtensions_Nodes_JsonGroup(o, collector)
636
670
  return super if !json_supported?
637
671
 
638
672
  if o.as_array