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
@@ -18,7 +18,23 @@ module ArelExtensions
18
18
  }.freeze
19
19
 
20
20
  # String functions
21
- def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
21
+ def visit_ArelExtensions_Nodes_ByteSize(o, collector)
22
+ # sqlite 3.43.0 (2023-08-24) introduced `octet_length`, but we still support older versions.
23
+ # https://sqlite.org/changes.html
24
+ collector << 'length(CAST('
25
+ collector = visit o.expr.coalesce(''), collector
26
+ collector << ' AS BLOB))'
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_IMatches(o, collector) # insensitive on ASCII
22
38
  collector = visit o.left.ci_collate, collector
23
39
  collector << ' LIKE '
24
40
  collector = visit o.right.ci_collate, collector
@@ -30,7 +46,7 @@ module ArelExtensions
30
46
  end
31
47
  end
32
48
 
33
- def visit_ArelExtensions_Nodes_AiMatches o, collector
49
+ def visit_ArelExtensions_Nodes_AiMatches(o, collector)
34
50
  collector = visit o.left.ai_collate, collector
35
51
  collector << ' LIKE '
36
52
  collector = visit o.right.ai_collate, collector
@@ -42,7 +58,7 @@ module ArelExtensions
42
58
  end
43
59
  end
44
60
 
45
- def visit_ArelExtensions_Nodes_AiIMatches o, collector
61
+ def visit_ArelExtensions_Nodes_AiIMatches(o, collector)
46
62
  collector = visit o.left.collate(true, true), collector
47
63
  collector << ' LIKE '
48
64
  collector = visit o.right.collate(true, true), collector
@@ -54,7 +70,7 @@ module ArelExtensions
54
70
  end
55
71
  end
56
72
 
57
- def visit_ArelExtensions_Nodes_SMatches o, collector
73
+ def visit_ArelExtensions_Nodes_SMatches(o, collector)
58
74
  collector = visit o.left.collate, collector
59
75
  collector << ' LIKE '
60
76
  collector = visit o.right.collate, collector
@@ -66,7 +82,7 @@ module ArelExtensions
66
82
  end
67
83
  end
68
84
 
69
- def visit_ArelExtensions_Nodes_Collate o, collector
85
+ def visit_ArelExtensions_Nodes_Collate(o, collector)
70
86
  if o.ai
71
87
  collector = visit o.expressions.first, collector
72
88
  collector << ' COLLATE NOACCENTS'
@@ -80,7 +96,7 @@ module ArelExtensions
80
96
  collector
81
97
  end
82
98
 
83
- def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
99
+ def visit_ArelExtensions_Nodes_IDoesNotMatch(o, collector)
84
100
  collector = visit o.left.lower, collector
85
101
  collector << ' NOT LIKE '
86
102
  collector = visit o.right.lower(o.right), collector
@@ -93,7 +109,7 @@ module ArelExtensions
93
109
  end
94
110
 
95
111
  # Date operations
96
- def visit_ArelExtensions_Nodes_DateAdd o, collector
112
+ def visit_ArelExtensions_Nodes_DateAdd(o, collector)
97
113
  collector << 'date('
98
114
  collector = visit o.expressions.first, collector
99
115
  collector << COMMA
@@ -102,7 +118,7 @@ module ArelExtensions
102
118
  collector
103
119
  end
104
120
 
105
- def visit_ArelExtensions_Nodes_DateDiff o, collector
121
+ def visit_ArelExtensions_Nodes_DateDiff(o, collector)
106
122
  case o.left_node_type
107
123
  when :ruby_time, :datetime, :time
108
124
  collector << "strftime('%s', "
@@ -119,14 +135,14 @@ module ArelExtensions
119
135
  collector
120
136
  end
121
137
 
122
- def visit_ArelExtensions_Nodes_Duration o, collector
138
+ def visit_ArelExtensions_Nodes_Duration(o, collector)
123
139
  collector << "strftime('#{DATE_MAPPING[o.left]}'#{COMMA}"
124
140
  collector = visit o.right, collector
125
141
  collector << ')'
126
142
  collector
127
143
  end
128
144
 
129
- def visit_ArelExtensions_Nodes_Locate o, collector
145
+ def visit_ArelExtensions_Nodes_Locate(o, collector)
130
146
  collector << 'instr('
131
147
  collector = visit o.expr, collector
132
148
  collector << COMMA
@@ -135,7 +151,7 @@ module ArelExtensions
135
151
  collector
136
152
  end
137
153
 
138
- def visit_ArelExtensions_Nodes_Concat o, collector
154
+ def visit_ArelExtensions_Nodes_Concat(o, collector)
139
155
  collector << '('
140
156
  o.expressions.each_with_index { |arg, i|
141
157
  collector = visit arg, collector
@@ -145,7 +161,9 @@ module ArelExtensions
145
161
  collector
146
162
  end
147
163
 
148
- def visit_ArelExtensions_Nodes_Substring o, collector
164
+ def visit_ArelExtensions_Nodes_Substring(o, collector)
165
+ return visit(o.range_substring_node, collector) if o.range?
166
+
149
167
  collector << 'SUBSTR('
150
168
  o.expressions.each_with_index { |arg, i|
151
169
  collector << COMMA if i != 0
@@ -155,21 +173,21 @@ module ArelExtensions
155
173
  collector
156
174
  end
157
175
 
158
- def visit_ArelExtensions_Nodes_IsNull o, collector
176
+ def visit_ArelExtensions_Nodes_IsNull(o, collector)
159
177
  collector = visit o.expr, collector
160
178
  collector << ' IS NULL'
161
179
  collector
162
180
  end
163
181
 
164
- def visit_ArelExtensions_Nodes_IsNotNull o, collector
182
+ def visit_ArelExtensions_Nodes_IsNotNull(o, collector)
165
183
  collector = visit o.expr, collector
166
- collector << ' IS NOT NULL'
167
- collector
184
+ collector << ' IS NOT NULL'
185
+ collector
168
186
  end
169
187
 
170
- def visit_ArelExtensions_Nodes_Rand o, collector
188
+ def visit_ArelExtensions_Nodes_Rand(o, collector)
171
189
  collector << 'RANDOM('
172
- if o.left != nil && o.right != nil
190
+ if !o.left.nil? && !o.right.nil?
173
191
  collector = visit o.left, collector
174
192
  collector << COMMA
175
193
  collector = visit o.right, collector
@@ -178,21 +196,19 @@ module ArelExtensions
178
196
  collector
179
197
  end
180
198
 
181
- def visit_Arel_Nodes_Regexp o, collector
199
+ def visit_Arel_Nodes_Regexp(o, collector)
182
200
  collector = visit o.left, collector
183
201
  collector << ' REGEXP'
184
- collector = visit o.right, collector
185
- collector
202
+ visit o.right, collector
186
203
  end
187
204
 
188
- def visit_Arel_Nodes_NotRegexp o, collector
205
+ def visit_Arel_Nodes_NotRegexp(o, collector)
189
206
  collector = visit o.left, collector
190
207
  collector << ' NOT REGEXP '
191
- collector = visit o.right, collector
192
- collector
208
+ visit o.right, collector
193
209
  end
194
210
 
195
- def visit_ArelExtensions_Nodes_Wday o, collector
211
+ def visit_ArelExtensions_Nodes_Wday(o, collector)
196
212
  collector << "STRFTIME('%w',"
197
213
  collector = visit o.date, collector
198
214
  collector << ')'
@@ -207,7 +223,7 @@ module ArelExtensions
207
223
  # END
208
224
  # AS FLOAT
209
225
  # )
210
- def visit_ArelExtensions_Nodes_Floor o, collector
226
+ def visit_ArelExtensions_Nodes_Floor(o, collector)
211
227
  collector << 'CAST(CASE WHEN '
212
228
  collector = visit o.left, collector
213
229
  collector << ' >= 0 THEN CAST('
@@ -224,7 +240,7 @@ module ArelExtensions
224
240
  collector
225
241
  end
226
242
 
227
- def visit_ArelExtensions_Nodes_Ceil o, collector
243
+ def visit_ArelExtensions_Nodes_Ceil(o, collector)
228
244
  collector << 'CASE WHEN ROUND('
229
245
  collector = visit o.left, collector
230
246
  collector << ', 1) > ROUND('
@@ -237,8 +253,8 @@ module ArelExtensions
237
253
  collector
238
254
  end
239
255
 
240
- if Arel::VERSION.to_i < 7
241
- def visit_ArelExtensions_InsertManager_BulkValues o, collector
256
+ if AREL_VERSION < V7
257
+ def visit_ArelExtensions_InsertManager_BulkValues(o, collector)
242
258
  o.left.each_with_index do |row, idx|
243
259
  collector << 'SELECT '
244
260
  len = row.length - 1
@@ -253,14 +269,14 @@ module ArelExtensions
253
269
  collector << quote(attr.name)
254
270
  end
255
271
  end
256
- collector << COMMA unless i == len
272
+ collector << COMMA unless i == len
257
273
  }
258
274
  collector << ' UNION ALL ' unless idx == o.left.length - 1
259
275
  end
260
276
  collector
261
277
  end
262
278
  else
263
- def visit_ArelExtensions_InsertManager_BulkValues o, collector
279
+ def visit_ArelExtensions_InsertManager_BulkValues(o, collector)
264
280
  o.left.each_with_index do |row, idx|
265
281
  collector << 'SELECT '
266
282
  len = row.length - 1
@@ -281,7 +297,7 @@ module ArelExtensions
281
297
  collector << quote(attr.name)
282
298
  end
283
299
  end
284
- collector << COMMA unless i == len
300
+ collector << COMMA unless i == len
285
301
  }
286
302
  collector << ' UNION ALL ' unless idx == o.left.length - 1
287
303
  end
@@ -289,7 +305,7 @@ module ArelExtensions
289
305
  end
290
306
  end
291
307
 
292
- def visit_ArelExtensions_Nodes_Union o, collector
308
+ def visit_ArelExtensions_Nodes_Union(o, collector)
293
309
  collector =
294
310
  if o.left.is_a?(Arel::SelectManager)
295
311
  visit o.left.ast, collector
@@ -297,16 +313,14 @@ module ArelExtensions
297
313
  visit o.left, collector
298
314
  end
299
315
  collector << ' UNION '
300
- collector =
301
- if o.right.is_a?(Arel::SelectManager)
302
- visit o.right.ast, collector
303
- else
304
- visit o.right, collector
305
- end
306
- collector
316
+ if o.right.is_a?(Arel::SelectManager)
317
+ visit o.right.ast, collector
318
+ else
319
+ visit o.right, collector
320
+ end
307
321
  end
308
322
 
309
- def visit_ArelExtensions_Nodes_UnionAll o, collector
323
+ def visit_ArelExtensions_Nodes_UnionAll(o, collector)
310
324
  collector =
311
325
  if o.left.is_a?(Arel::SelectManager)
312
326
  visit o.left.ast, collector
@@ -314,16 +328,14 @@ module ArelExtensions
314
328
  visit o.left, collector
315
329
  end
316
330
  collector << ' UNION ALL '
317
- collector =
318
- if o.right.is_a?(Arel::SelectManager)
319
- visit o.right.ast, collector
320
- else
321
- visit o.right, collector
322
- end
323
- collector
331
+ if o.right.is_a?(Arel::SelectManager)
332
+ visit o.right.ast, collector
333
+ else
334
+ visit o.right, collector
335
+ end
324
336
  end
325
337
 
326
- def get_time_converted element
338
+ def get_time_converted(element)
327
339
  if element.is_a?(Time)
328
340
  Arel::Nodes::NamedFunction.new('STRFTIME', [element, '%H:%M:%S'])
329
341
  elsif element.is_a?(Arel::Attributes::Attribute)
@@ -339,39 +351,35 @@ module ArelExtensions
339
351
  end
340
352
 
341
353
  remove_method(:visit_Arel_Nodes_GreaterThanOrEqual) rescue nil
342
- def visit_Arel_Nodes_GreaterThanOrEqual o, collector
354
+ def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
343
355
  collector = visit get_time_converted(o.left), collector
344
356
  collector << ' >= '
345
- collector = visit get_time_converted(o.right), collector
346
- collector
357
+ visit get_time_converted(o.right), collector
347
358
  end
348
359
 
349
360
  remove_method(:visit_Arel_Nodes_GreaterThan) rescue nil
350
- def visit_Arel_Nodes_GreaterThan o, collector
361
+ def visit_Arel_Nodes_GreaterThan(o, collector)
351
362
  collector = visit get_time_converted(o.left), collector
352
363
  collector << ' > '
353
- collector = visit get_time_converted(o.right), collector
354
- collector
364
+ visit get_time_converted(o.right), collector
355
365
  end
356
366
 
357
367
  remove_method(:visit_Arel_Nodes_LessThanOrEqual) rescue nil
358
- def visit_Arel_Nodes_LessThanOrEqual o, collector
368
+ def visit_Arel_Nodes_LessThanOrEqual(o, collector)
359
369
  collector = visit get_time_converted(o.left), collector
360
370
  collector << ' <= '
361
- collector = visit get_time_converted(o.right), collector
362
- collector
371
+ visit get_time_converted(o.right), collector
363
372
  end
364
373
 
365
374
  remove_method(:visit_Arel_Nodes_LessThan) rescue nil
366
- def visit_Arel_Nodes_LessThan o, collector
375
+ def visit_Arel_Nodes_LessThan(o, collector)
367
376
  collector = visit get_time_converted(o.left), collector
368
377
  collector << ' < '
369
- collector = visit get_time_converted(o.right), collector
370
- collector
378
+ visit get_time_converted(o.right), collector
371
379
  end
372
380
 
373
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
374
- def visit_Arel_Nodes_As o, collector
381
+ alias old_visit_Arel_Nodes_As visit_Arel_Nodes_As rescue nil
382
+ def visit_Arel_Nodes_As(o, collector)
375
383
  if o.left.is_a?(Arel::Nodes::Binary)
376
384
  collector << '('
377
385
  collector = visit o.left, collector
@@ -386,7 +394,7 @@ module ArelExtensions
386
394
  collector
387
395
  end
388
396
 
389
- def visit_ArelExtensions_Nodes_FormattedNumber o, collector
397
+ def visit_ArelExtensions_Nodes_FormattedNumber(o, collector)
390
398
  format = Arel::Nodes::NamedFunction.new('printf', [Arel.quoted(o.original_string), o.left])
391
399
  locale_map = NUMBER_COMMA_MAPPING[o.locale]
392
400
  if locale_map