arel_extensions 1.5.3 → 1.7.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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63ac168e55da77eacb9edfa70f025558721346a4912f225a2b35be1b7bd4eb66
4
- data.tar.gz: d24d852a75734d25306326ce3068ad541155f2643990e71eeedccbe823354d2d
3
+ metadata.gz: fc5e8faed3431c98442763629d3e67398798d70580bdb5137f90bd1b11947d8f
4
+ data.tar.gz: a8b396a11006278c2d0e067750d99d61c24a07712cecd189905c064aac4f8fe1
5
5
  SHA512:
6
- metadata.gz: ae560399c811449f49ad80139a244e2e8602b0e897b17ec2a58e0af3e99aa31e6e4c302fd78a32737817b03531bc86f4cfd3b929e149c2fa862af371a10b6b2a
7
- data.tar.gz: 581b12e386fc04cc4fd0dd7e7ab975a40ec6f077203f9d8350b665e7f679c8bd942ab2b30c4f6225cc3bb85dc1213247743e497e059bae83fe56d541235a8eb8
6
+ metadata.gz: 67eb687a130704304d0c9c1a36cc0dbc9e0f41e0ae882005e5b51ea1d066988f596472fa23847364160f502ca8b9c7831bba216665256f59f52cbc292f7006bd
7
+ data.tar.gz: 9b73530a338a85a478fd350089976aae94c359f9d80e9e94ca8b829404475f4ed11a6dfd9fca718eef930ea3c151712cd4da757b9696f66285db55e37382838e
@@ -24,10 +24,20 @@ jobs:
24
24
  matrix:
25
25
  versions:
26
26
  [
27
+ { ruby: "3.4", rails: 8_1, arelx: 2 },
28
+ { ruby: "3.4", rails: 8, arelx: 2 },
29
+ { ruby: "3.4", rails: 7_2, arelx: 2 },
30
+ { ruby: "3.4", rails: 7_1, arelx: 2 },
31
+ { ruby: "3.4", rails: 7, arelx: 2 },
32
+ { ruby: "3.4", rails: 6_1, arelx: 2 },
33
+ { ruby: "3.3", rails: 8_1, arelx: 2 },
34
+ { ruby: "3.3", rails: 8, arelx: 2 },
27
35
  { ruby: "3.3", rails: 7_2, arelx: 2 },
28
36
  { ruby: "3.3", rails: 7_1, arelx: 2 },
29
37
  { ruby: "3.3", rails: 7, arelx: 2 },
30
38
  { ruby: "3.3", rails: 6_1, arelx: 2 },
39
+ { ruby: "3.2", rails: 8_1, arelx: 2 },
40
+ { ruby: "3.2", rails: 8, arelx: 2 },
31
41
  { ruby: "3.2", rails: 7_2, arelx: 2 },
32
42
  { ruby: "3.2", rails: 7_1, arelx: 2 },
33
43
  { ruby: "3.2", rails: 7, arelx: 2 },
@@ -46,11 +56,6 @@ jobs:
46
56
  { ruby: "2.7", rails: 6_1, arelx: 2 },
47
57
  { ruby: "2.7", rails: 6, arelx: 2 },
48
58
  { ruby: "2.7", rails: 5_2, arelx: 1 },
49
- { ruby: "2.7", rails: 4_2, arelx: 1 },
50
- { ruby: "2.5", rails: 6_1, arelx: 2 },
51
- { ruby: "2.5", rails: 6, arelx: 2 },
52
- { ruby: "2.5", rails: 5_2, arelx: 1 },
53
- { ruby: "2.5", rails: 4_2, arelx: 1 },
54
59
  { ruby: jruby-9.2, rails: 6_1, arelx: 2 },
55
60
  { ruby: jruby-9.2, rails: 6, arelx: 2 },
56
61
  { ruby: jruby-9.2, rails: 5_2, arelx: 1 },
@@ -88,10 +93,20 @@ jobs:
88
93
  matrix:
89
94
  versions:
90
95
  [
96
+ { ruby: "3.4", rails: 8_1, arelx: 2 },
97
+ { ruby: "3.4", rails: 8, arelx: 2 },
98
+ { ruby: "3.4", rails: 7_2, arelx: 2 },
99
+ { ruby: "3.4", rails: 7_1, arelx: 2 },
100
+ { ruby: "3.4", rails: 7, arelx: 2 },
101
+ { ruby: "3.4", rails: 6_1, arelx: 2 },
102
+ { ruby: "3.3", rails: 8_1, arelx: 2 },
103
+ { ruby: "3.3", rails: 8, arelx: 2 },
91
104
  { ruby: "3.3", rails: 7_2, arelx: 2 },
92
105
  { ruby: "3.3", rails: 7_1, arelx: 2 },
93
106
  { ruby: "3.3", rails: 7, arelx: 2 },
94
107
  { ruby: "3.3", rails: 6_1, arelx: 2 },
108
+ { ruby: "3.2", rails: 8_1, arelx: 2 },
109
+ { ruby: "3.2", rails: 8, arelx: 2 },
95
110
  { ruby: "3.2", rails: 7_2, arelx: 2 },
96
111
  { ruby: "3.2", rails: 7_1, arelx: 2 },
97
112
  { ruby: "3.2", rails: 7, arelx: 2 },
@@ -110,15 +125,9 @@ jobs:
110
125
  { ruby: "2.7", rails: 6_1, arelx: 2 },
111
126
  { ruby: "2.7", rails: 6, arelx: 2 },
112
127
  { ruby: "2.7", rails: 5_2, arelx: 1 },
113
- { ruby: "2.7", rails: 4_2, arelx: 1 },
114
- { ruby: "2.5", rails: 6_1, arelx: 2 },
115
- { ruby: "2.5", rails: 6, arelx: 2 },
116
- { ruby: "2.5", rails: 5_2, arelx: 1 },
117
- { ruby: "2.5", rails: 4_2, arelx: 1 },
118
128
  { ruby: jruby-9.2, rails: 6_1, arelx: 2 },
119
129
  { ruby: jruby-9.2, rails: 6, arelx: 2 },
120
130
  { ruby: jruby-9.2, rails: 5_2, arelx: 1 },
121
- { ruby: jruby-9.2, rails: 4_2, arelx: 1 },
122
131
  { ruby: jruby-9.3, rails: 6_1, arelx: 2 },
123
132
  { ruby: jruby-9.3, rails: 6, arelx: 2 },
124
133
  { ruby: jruby-9.3, rails: 5_2, arelx: 1 },
@@ -152,10 +161,20 @@ jobs:
152
161
  fail-fast: false
153
162
  matrix:
154
163
  versions: [
164
+ { ruby: "3.4", rails: 8_1, arelx: 2 },
165
+ { ruby: "3.4", rails: 8, arelx: 2 },
166
+ { ruby: "3.4", rails: 7_2, arelx: 2 },
167
+ { ruby: "3.4", rails: 7_1, arelx: 2 },
168
+ { ruby: "3.4", rails: 7, arelx: 2 },
169
+ { ruby: "3.4", rails: 6_1, arelx: 2 },
170
+ { ruby: "3.3", rails: 8_1, arelx: 2 },
171
+ { ruby: "3.3", rails: 8, arelx: 2 },
155
172
  { ruby: "3.3", rails: 7_2, arelx: 2 },
156
173
  { ruby: "3.3", rails: 7_1, arelx: 2 },
157
174
  { ruby: "3.3", rails: 7, arelx: 2 },
158
175
  { ruby: "3.3", rails: 6_1, arelx: 2 },
176
+ { ruby: "3.2", rails: 8_1, arelx: 2 },
177
+ { ruby: "3.2", rails: 8, arelx: 2 },
159
178
  { ruby: "3.2", rails: 7_2, arelx: 2 },
160
179
  { ruby: "3.2", rails: 7_1, arelx: 2 },
161
180
  { ruby: "3.2", rails: 7, arelx: 2 },
@@ -174,15 +193,9 @@ jobs:
174
193
  { ruby: "2.7", rails: 6_1, arelx: 2 },
175
194
  { ruby: "2.7", rails: 6, arelx: 2 },
176
195
  { ruby: "2.7", rails: 5_2, arelx: 1 },
177
- { ruby: "2.7", rails: 4_2, arelx: 1 },
178
- { ruby: "2.5", rails: 6_1, arelx: 2 },
179
- { ruby: "2.5", rails: 6, arelx: 2 },
180
- { ruby: "2.5", rails: 5_2, arelx: 1 },
181
- { ruby: "2.5", rails: 4_2, arelx: 1 },
182
196
  { ruby: jruby-9.2, rails: 6_1, arelx: 2 },
183
197
  { ruby: jruby-9.2, rails: 6, arelx: 2 },
184
198
  { ruby: jruby-9.2, rails: 5_2, arelx: 1 },
185
- { ruby: jruby-9.2, rails: 4_2, arelx: 1 },
186
199
  { ruby: jruby-9.3, rails: 6_1, arelx: 2 },
187
200
  { ruby: jruby-9.3, rails: 6, arelx: 2 },
188
201
  { ruby: jruby-9.3, rails: 5_2, arelx: 1 },
@@ -241,10 +254,20 @@ jobs:
241
254
  fail-fast: false
242
255
  matrix:
243
256
  versions: [
257
+ { ruby: "3.4", rails: 8_1, arelx: 2 },
258
+ { ruby: "3.4", rails: 8, arelx: 2 },
259
+ { ruby: "3.4", rails: 7_2, arelx: 2 },
260
+ { ruby: "3.4", rails: 7_1, arelx: 2 },
261
+ { ruby: "3.4", rails: 7, arelx: 2 },
262
+ { ruby: "3.4", rails: 6_1, arelx: 2 },
263
+ { ruby: "3.3", rails: 8_1, arelx: 2 },
264
+ { ruby: "3.3", rails: 8, arelx: 2 },
244
265
  { ruby: "3.3", rails: 7_2, arelx: 2 },
245
266
  { ruby: "3.3", rails: 7_1, arelx: 2 },
246
267
  { ruby: "3.3", rails: 7, arelx: 2 },
247
268
  { ruby: "3.3", rails: 6_1, arelx: 2 },
269
+ { ruby: "3.2", rails: 8_1, arelx: 2 },
270
+ { ruby: "3.2", rails: 8, arelx: 2 },
248
271
  { ruby: "3.2", rails: 7_2, arelx: 2 },
249
272
  { ruby: "3.2", rails: 7_1, arelx: 2 },
250
273
  { ruby: "3.2", rails: 7, arelx: 2 },
@@ -263,35 +286,56 @@ jobs:
263
286
  { ruby: "2.7", rails: 6_1, arelx: 2 },
264
287
  { ruby: "2.7", rails: 6, arelx: 2 },
265
288
  { ruby: "2.7", rails: 5_2, arelx: 1 },
266
- { ruby: "2.7", rails: 4_2, arelx: 1 },
267
- { ruby: "2.5", rails: 6_1, arelx: 2 },
268
- { ruby: "2.5", rails: 6, arelx: 2 },
269
- { ruby: "2.5", rails: 5_2, arelx: 1 },
270
- { ruby: "2.5", rails: 4_2, arelx: 1 },
271
289
  { ruby: jruby-9.2, rails: 6_1, arelx: 2 },
272
290
  { ruby: jruby-9.2, rails: 6, arelx: 2 },
273
291
  { ruby: jruby-9.2, rails: 5_2, arelx: 1 },
274
- { ruby: jruby-9.2, rails: 4_2, arelx: 1 },
275
292
  { ruby: jruby-9.3, rails: 6_1, arelx: 2 },
276
293
  { ruby: jruby-9.3, rails: 6, arelx: 2 },
277
294
  { ruby: jruby-9.3, rails: 5_2, arelx: 1 },
278
295
  ]
279
- services:
280
- mysql:
281
- image: mysql:5.7
282
- env:
283
- MYSQL_ALLOW_EMPTY_PASSWORD: true
284
- MYSQL_USERNAME: root
285
- MYSQL_DATABASE: arelx_test
286
- ports:
287
- - 3306:3306
288
- options: >-
289
- --health-cmd="mysqladmin ping"
290
- --health-interval=10s
291
- --health-timeout=5s
292
- --health-retries=3
296
+ # TODO: restore the service. it's far simpler, but since we're testing old
297
+ # mysql, and we want utf-8 by default, we're currently forced to avoid the
298
+ # service, and do it as a step. Maybe there's a better solution, who knows?
299
+ #
300
+ # services:
301
+ # mysql:
302
+ # image: mysql:5.7
303
+ # env:
304
+ # MYSQL_ALLOW_EMPTY_PASSWORD: true
305
+ # MYSQL_USERNAME: root
306
+ # MYSQL_DATABASE: arelx_test
307
+ # ports:
308
+ # - 3306:3306
309
+ # options: >-
310
+ # --health-cmd="mysqladmin ping"
311
+ # --health-interval=10s
312
+ # --health-timeout=5s
313
+ # --health-retries=3
314
+ #
293
315
  steps:
294
316
  - uses: actions/checkout@v2
317
+
318
+ - name: Start MySQL with UTF-8
319
+ run: |
320
+ docker run -d \
321
+ --name mysql \
322
+ -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
323
+ -e MYSQL_DATABASE=arelx_test \
324
+ -p 3306:3306 \
325
+ --health-cmd="mysqladmin ping" \
326
+ --health-interval=10s \
327
+ --health-timeout=5s \
328
+ --health-retries=3 \
329
+ mysql:5.7 \
330
+ --character-set-server=utf8mb4
331
+
332
+ - name: Wait for MySQL
333
+ run: |
334
+ until docker exec mysql mysqladmin ping --silent; do
335
+ echo 'Waiting for MySQL...'
336
+ sleep 2
337
+ done
338
+
295
339
  - name: Set up Ruby
296
340
  uses: ruby/setup-ruby@v1
297
341
  with:
@@ -325,10 +369,21 @@ jobs:
325
369
  fail-fast: false
326
370
  matrix:
327
371
  versions: [
372
+ { ruby: "3.4", rails: 8_1, arelx: 2 },
373
+ { ruby: "3.4", rails: 8, arelx: 2 },
374
+ { ruby: "3.4", rails: 7_2, arelx: 2 },
375
+ { ruby: "3.4", rails: 7_1, arelx: 2 },
376
+ { ruby: "3.4", rails: 7, arelx: 2 },
377
+ { ruby: "3.4", rails: 6_1, arelx: 2 },
378
+ { ruby: "3.3", rails: 8_1, arelx: 2 },
379
+ { ruby: "3.3", rails: 8, arelx: 2 },
380
+ { ruby: "3.3", rails: 7_2, arelx: 2 },
328
381
  { ruby: "3.3", rails: 7_1, arelx: 2 },
329
382
  { ruby: "3.3", rails: 7, arelx: 2 },
330
383
  { ruby: "3.3", rails: 6_1, arelx: 2 },
331
384
  { ruby: "3.3", rails: 6, arelx: 2 },
385
+ { ruby: "3.2", rails: 8_1, arelx: 2 },
386
+ { ruby: "3.2", rails: 8, arelx: 2 },
332
387
  { ruby: "3.2", rails: 7_1, arelx: 2 },
333
388
  { ruby: "3.2", rails: 7, arelx: 2 },
334
389
  { ruby: "3.2", rails: 6_1, arelx: 2 },
@@ -343,15 +398,9 @@ jobs:
343
398
  { ruby: "2.7", rails: 6_1, arelx: 2 },
344
399
  { ruby: "2.7", rails: 6, arelx: 2 },
345
400
  { ruby: "2.7", rails: 5_2, arelx: 1 },
346
- { ruby: "2.7", rails: 4_2, arelx: 1 },
347
- { ruby: "2.5", rails: 6_1, arelx: 2 },
348
- { ruby: "2.5", rails: 6, arelx: 2 },
349
- { ruby: "2.5", rails: 5_2, arelx: 1 },
350
- { ruby: "2.5", rails: 4_2, arelx: 1 },
351
401
  # {ruby: jruby-9.2, rails: 6_1, arelx: 2},
352
402
  # {ruby: jruby-9.2, rails: 6, arelx: 2},
353
403
  { ruby: jruby-9.2, rails: 5_2, arelx: 1 },
354
- { ruby: jruby-9.2, rails: 4_2, arelx: 1 },
355
404
  # See comments on 9.4 to understand why these are disabled for now.
356
405
  # {ruby: jruby-9.3, rails: 6_1, arelx: 2},
357
406
  # {ruby: jruby-9.3, rails: 6, arelx: 2},
data/.gitignore CHANGED
@@ -1,7 +1,8 @@
1
1
  *.DS_Store
2
+ *.jar
3
+ *.lock
2
4
  *.swp
3
5
  .bundle
4
- Gemfile.lock
5
6
  config/database.yml
6
7
  coverage/*
7
8
  debug.log
data/.rubocop.yml CHANGED
@@ -1,7 +1,26 @@
1
+ plugins:
2
+ - rubocop-performance
3
+
1
4
  AllCops:
2
- DisabledByDefault: true
5
+ NewCops: enable
6
+ TargetRubyVersion: 2.7
7
+ SuggestExtensions: false
8
+ # TODO: enable for tests.
3
9
  Exclude:
4
- - "vendor/**/*"
10
+ - vendor/**/*
11
+ - dev/**/*
12
+ - test/**/*
13
+
14
+ # TODO: enable.
15
+ Gemspec/RequireMFA:
16
+ Enabled: false
17
+
18
+ # TODO: enable.
19
+ Gemspec/RequiredRubyVersion:
20
+ Enabled: false
21
+
22
+ Layout/ArgumentAlignment:
23
+ Enabled: false
5
24
 
6
25
  Layout/EndOfLine:
7
26
  Enabled: true
@@ -15,6 +34,9 @@ Layout/IndentationWidth:
15
34
  Layout/LineLength:
16
35
  Enabled: false
17
36
 
37
+ Layout/MultilineMethodCallIndentation:
38
+ EnforcedStyle: indented
39
+
18
40
  Layout/SpaceAfterComma:
19
41
  Enabled: true
20
42
 
@@ -28,15 +50,66 @@ Layout/SpaceInsideHashLiteralBraces:
28
50
  Enabled: true
29
51
  EnforcedStyle: no_space
30
52
 
53
+ Lint/BinaryOperatorWithIdenticalOperands:
54
+ Enabled: true
55
+ Exclude:
56
+ - test/with_ar/all_agnostic_test.rb
57
+
58
+ # TODO: should we enable it? It's complaining about things like (1*2+3)
59
+ Lint/AmbiguousOperatorPrecedence:
60
+ Enabled: false
61
+
31
62
  Layout/TrailingEmptyLines:
32
63
  Enabled: true
33
64
 
65
+ # TODO: enable.
66
+ Metrics/AbcSize:
67
+ Enabled: false
68
+
69
+ # TODO: enable.
34
70
  Metrics/BlockLength:
35
71
  Enabled: false
36
72
 
73
+ Metrics/BlockNesting:
74
+ Enabled: false
75
+
76
+ # TODO: enable.
77
+ Metrics/MethodLength:
78
+ Enabled: false
79
+
80
+ Metrics/ModuleLength:
81
+ Enabled: false
82
+
83
+ # TODO: enable.
84
+ Metrics/CyclomaticComplexity:
85
+ Enabled: false
86
+
87
+ # TODO: enable.
88
+ Metrics/PerceivedComplexity:
89
+ Enabled: false
90
+
91
+ Naming/AsciiIdentifiers:
92
+ Enabled: true
93
+ Exclude:
94
+ - lib/arel_extensions/boolean_functions.rb
95
+
96
+ Naming/MethodName:
97
+ Exclude:
98
+ - lib/arel_extensions/boolean_functions.rb
99
+
100
+ # TODO: enable.
101
+ Naming/MethodParameterName:
102
+ Enabled: false
103
+
37
104
  Naming/FileName:
38
105
  Enabled: true
39
106
 
107
+ Style/BlockDelimiters:
108
+ Enabled: false
109
+
110
+ Style/ClassAndModuleChildren:
111
+ Enabled: false
112
+
40
113
  Style/CollectionMethods:
41
114
  Enabled: true
42
115
 
@@ -49,12 +122,33 @@ Style/CommentAnnotation:
49
122
  Style/ConditionalAssignment:
50
123
  Enabled: true
51
124
 
125
+ # TODO: enable.
126
+ Style/Documentation:
127
+ Enabled: false
128
+
129
+ Style/EachWithObject:
130
+ Enabled: false
131
+
52
132
  Style/EmptyElse:
53
133
  Enabled: true
54
134
 
55
135
  Style/Encoding:
56
136
  Enabled: true
57
137
 
138
+ Style/FormatString:
139
+ Enabled: false
140
+
141
+ # TODO: enable.
142
+ Style/GlobalVars:
143
+ Enabled: false
144
+
145
+ # TODO: enable.
146
+ Style/GuardClause:
147
+ Enabled: false
148
+
149
+ Style/IfUnlessModifier:
150
+ Enabled: false
151
+
58
152
  Style/HashSyntax:
59
153
  Enabled: true
60
154
  EnforcedStyle: ruby19
@@ -65,9 +159,23 @@ Style/MethodCallWithArgsParentheses:
65
159
  Style/MethodCallWithoutArgsParentheses:
66
160
  Enabled: true
67
161
 
162
+ Style/MultipleComparison:
163
+ Enabled: true
164
+ Exclude:
165
+ - lib/arel_extensions/boolean_functions.rb
166
+
68
167
  Style/NegatedIf:
69
168
  Enabled: false
70
169
 
170
+ Style/NegatedIfElseCondition:
171
+ Enabled: false
172
+
173
+ Style/NegatedWhile:
174
+ Enabled: false
175
+
176
+ Style/NestedTernary:
177
+ Enabled: false
178
+
71
179
  Style/NumericLiterals:
72
180
  Enabled: true
73
181
 
@@ -80,10 +188,19 @@ Style/RedundantRegexpCharacterClass:
80
188
  Style/RedundantReturn:
81
189
  Enabled: true
82
190
 
191
+ # TODO: enable.
192
+ # We have some `... rescue nil` going on, let's keep it this way for now.
193
+ Style/RescueModifier:
194
+ Enabled: false
195
+
83
196
  # Even when conservative, this is unsafe.
84
- #Style/StringConcatenation:
85
- # Enabled: true
86
- # Mode: 'conservative'
197
+ # Style/StringConcatenation:
198
+ # Enabled: true
199
+ # Mode: 'conservative'
200
+
201
+ # This detects User.at[:id] + '1' as string concatenation, so never enable.
202
+ Style/StringConcatenation:
203
+ Enabled: false
87
204
 
88
205
  Style/StringLiterals:
89
206
  Enabled: true
@@ -91,9 +208,18 @@ Style/StringLiterals:
91
208
  Style/SymbolArray:
92
209
  Enabled: true
93
210
 
211
+ Style/UnlessElse:
212
+ Enabled: false
213
+
214
+ Style/WhileUntilDo:
215
+ Enabled: false
216
+
94
217
  Style/WordArray:
95
218
  Enabled: true
96
219
 
220
+ Style/YodaCondition:
221
+ Enabled: false
222
+
97
223
  # Performance cops have been transferred to rubocop-performance gem.
98
224
  require: rubocop-performance
99
225
 
data/Makefile ADDED
@@ -0,0 +1,48 @@
1
+ COMPOSE_FILE := dev/compose.yaml
2
+ DC := docker compose -f $(COMPOSE_FILE)
3
+
4
+ .PHONY: all clean down install lint publish rebuild shell test up
5
+
6
+ all: clean install
7
+
8
+ clean:
9
+ rm -rf .bundle Gemfile.lock vendor
10
+
11
+ down:
12
+ $(DC) down
13
+
14
+ install:
15
+ bundle install
16
+
17
+ lint:
18
+ bundle exec rubocop --config .rubocop.yml --require rubocop-performance
19
+
20
+ lint-fix:
21
+ bundle exec rubocop --config .rubocop.yml -a
22
+
23
+ local-%:
24
+ @version="$*"; \
25
+ file="gemfiles/rails$${version//./_}.gemfile"; \
26
+ if [ ! -f "$$file" ]; then \
27
+ echo "No such Gemfile: $$file"; \
28
+ exit 1; \
29
+ fi; \
30
+ echo "Using $$file"; \
31
+ bundle config set --local gemfile "$$file"
32
+
33
+ publish:
34
+ ./bin/publish
35
+
36
+ rebuild:
37
+ $(DC) build --no-cache
38
+
39
+ # Jump into the container
40
+ shell: up
41
+ $(DC) exec arelx bash
42
+
43
+ test:
44
+ bundle exec rake test
45
+
46
+ # Boot everything and keep it running (daemon mode)
47
+ up:
48
+ $(DC) up -d
data/NEWS.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## [unreleased]
4
4
 
5
+ ## Release v2.5.0/v1.7.0 (02-09-2026)
6
+
7
+ - Fix a typo preventing optimizer hints from being applied on SELECT in MySQL.
8
+ - Fix a bug (crash) in Group Concat of MSSQL.
9
+ - Fix a crash when building a JSON document from numeric literal values (e.g. `Arel.json(col => 1)`), on sqlite and mssql.
10
+ - MS SQL: string casts and MD5 input now use `varchar(MAX)`, so long strings are
11
+ no longer truncated at 30 characters (the default when only `varchar` is specified).
12
+ - PostgreSQL: JSON creation from non-JSON text now encodes it (`to_jsonb` instead of a
13
+ bare `::jsonb` cast), and `json.set(key, nil)` sets the JSON null member instead of the db's NULL.
14
+ - PostgreSQL: an empty JSON array (`Arel.json([])`) is now rendered as `'[]'::jsonb`
15
+ instead of `to_jsonb(array[])`.
16
+ - JSON: Booleans (`true`/`false`) are now supported as JSON values, whether as literals
17
+ (`Arel.json({ col => true })`) or boolean columns (`Arel.json({ col => bool_col })`).
18
+ - String slicing: the `[range..]` syntax, and calls to `substring` now behave exactly as in Ruby and MySQL, notably handling negative and beginless/endless indices.
19
+
20
+ ## Release v2.4.0/v1.6.0 (23-12-2025)
21
+
22
+ - Drop supoprt for Ruby < 2.7.
23
+ - Drop support for Rails < 5.2.
24
+ - Add support for Rails 8 and 8.1.
25
+ - Add `byte_size` and `char_length`. They should replace all uses of `length` because it's inconsistent across vendors; it can surprise you and give you byte size when you expect string length.
26
+
5
27
  ## Release v2.3.3/v1.5.3 (11-02-2025)
6
28
 
7
29
  - Fix the `&` operator which does `find_in_set` for mysql and postgres, accepting strings and integers.
data/README.md CHANGED
@@ -31,7 +31,7 @@ Most of the features will work just by adding the gem to your Gemfiles. To make
31
31
  ArelExtensions::CommonSqlFunctions.new(ActiveRecord::Base.connection).add_sql_functions()
32
32
  ```
33
33
 
34
- It will add common SQL features in your DB to align ti with current routines. Technically, it will execute SQL scripts from init folder.
34
+ It will add common SQL features in your DB to align it with current routines. Technically, it will execute SQL scripts from init folder.
35
35
 
36
36
 
37
37
  ## Examples
@@ -195,7 +195,7 @@ by the RDBMS.
195
195
  Warning:
196
196
 
197
197
  - ⚠️ Time Zone names are specific to each RDBMS. While `PostgreSQL` and `MySQL`
198
- have overlaping names (the ones prefixed with `posix`), you should always
198
+ have overlapping names (the ones prefixed with `posix`), you should always
199
199
  read your vendor's documentation. `SQL Server` is a black sheep and has its
200
200
  own conventions.
201
201
  - ⚠️ Daylight saving is managed by the RDBMS vendor. Choose the approptiate time
@@ -345,7 +345,7 @@ User.connection.execute(insert_manager.to_sql)
345
345
  <td class="ok">✔</td>
346
346
  </tr>
347
347
  <tr>
348
- <th class="tg-ffjm" rowspan="17"><div>String functions</div></th>
348
+ <th class="tg-ffjm" rowspan="21"><div>String functions</div></th>
349
349
  <td class="tg-yw4l">CONCAT<br>column + "string"</td>
350
350
  <td class="ok">✔</td>
351
351
  <td class="ok">✔</td>
@@ -373,7 +373,25 @@ User.connection.execute(insert_manager.to_sql)
373
373
  <td class="tg-j6lv">LOWER() LIKE LOWER()</td>
374
374
  </tr>
375
375
  <tr>
376
- <td class="tg-yw4l">LENGTH<br>column.length</td>
376
+ <td class="tg-yw4l">LENGTH<br>column.char_length</td>
377
+ <td class="ok">✔</td>
378
+ <td class="ok">✔</td>
379
+ <td class="ok">✔</td>
380
+ <td class="ok">✔</td>
381
+ <td class="tg-j6lv">✔</td>
382
+ <td class="ok">not implemented</td>
383
+ </tr>
384
+ <tr>
385
+ <td class="tg-yw4l">LENGTH (aka octet_length)<br>column.byte_size</td>
386
+ <td class="ok">✔</td>
387
+ <td class="ok">✔</td>
388
+ <td class="ok">✔</td>
389
+ <td class="ok">✔</td>
390
+ <td class="tg-j6lv">✔</td>
391
+ <td class="ok">not implemented</td>
392
+ </tr>
393
+ <tr>
394
+ <td class="tg-yw4l">LENGTH<br>column.length<br>⚠️ not portable, prefer char_length or byte_size</td>
377
395
  <td class="ok">✔</td>
378
396
  <td class="ok">✔</td>
379
397
  <td class="ok">✔</td>
@@ -472,7 +490,7 @@ User.connection.execute(insert_manager.to_sql)
472
490
  <td class="ok">✔</td>
473
491
  </tr>
474
492
  <tr>
475
- <td class="tg-yw4l">SUBSTRING<br/>column[1..2]<br/>column.substring(1)<br/>column.substring(1, 1)</td>
493
+ <td class="tg-yw4l">SUBSTRING (start/length)<br/>column.substring(1)<br/>column.substring(1, 1)<br/>column[1]<br/>column[0, 2]</td>
476
494
  <td class="ok">✔</td>
477
495
  <td class="tg-j6lv">SUBSTR()</td>
478
496
  <td class="tg-j6lv">SUBSTR()</td>
@@ -480,6 +498,15 @@ User.connection.execute(insert_manager.to_sql)
480
498
  <td class="ok">✔</td>
481
499
  <td class="ok">✔</td>
482
500
  </tr>
501
+ <tr>
502
+ <td class="tg-yw4l">SUBSTRING (Ruby range slicing)<br/>column[1..2]<br/>column[-2..]<br/>column[..2]<br/>⚠️ empty-string results read as NULL on Oracle</td>
503
+ <td class="ok">✔</td>
504
+ <td class="ok">✔</td>
505
+ <td class="ok">✔</td>
506
+ <td class="ok">✔</td>
507
+ <td class="ok">✔</td>
508
+ <td class="tg-j6lv">not implemented</td>
509
+ </tr>
483
510
  <tr>
484
511
  <td class="tg-yw4l">TRIM (leading)<br>column.trim("LEADING","M")</td>
485
512
  <td class="ok">✔</td>
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler'
2
4
  Bundler::GemHelper.install_tasks name: 'arel_extensions'
3
5
 
@@ -51,7 +53,7 @@ end
51
53
 
52
54
  # Useful shorthands.
53
55
  namespace :test do
54
- task :sql => :to_sql
55
- task :pg => :postgresql
56
- task :postgres => :postgresql
56
+ task sql: :to_sql
57
+ task pg: :postgresql
58
+ task postgres: :postgresql
57
59
  end
@@ -1,4 +1,6 @@
1
- $:.push File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
2
4
  require 'arel_extensions/version'
3
5
 
4
6
  Gem::Specification.new do |s|
@@ -17,11 +19,7 @@ Gem::Specification.new do |s|
17
19
 
18
20
  # Manifest
19
21
  s.files = `git ls-files`.split("\n")
20
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
22
  s.require_paths = ['lib']
22
23
 
23
24
  s.add_dependency('arel', '>= 6.0')
24
-
25
- s.add_development_dependency('minitest', '~> 5.9')
26
- s.add_development_dependency('rake', '~> 12.3.3')
27
25
  end