arel_extensions 2.1.5 → 2.1.7
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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +156 -153
- data/NEWS.md +32 -0
- data/README.md +151 -83
- data/appveyor.yml +9 -0
- data/arel_extensions.gemspec +0 -1
- data/gemfiles/{rails4.gemfile → rails4_2.gemfile} +12 -3
- data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +0 -0
- data/gemfiles/rails6_1.gemfile +1 -1
- data/gemfiles/rails7.gemfile +1 -1
- data/gemspecs/arel_extensions-v1.gemspec +0 -1
- data/gemspecs/arel_extensions-v2.gemspec +0 -1
- data/lib/arel_extensions/date_duration.rb +5 -0
- data/lib/arel_extensions/nodes/case.rb +4 -3
- data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
- data/lib/arel_extensions/nodes/rollup.rb +36 -0
- data/lib/arel_extensions/nodes/select.rb +10 -0
- data/lib/arel_extensions/null_functions.rb +16 -0
- data/lib/arel_extensions/string_functions.rb +1 -0
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +97 -0
- data/lib/arel_extensions/visitors/mysql.rb +89 -21
- data/lib/arel_extensions/visitors/oracle.rb +21 -0
- data/lib/arel_extensions/visitors/postgresql.rb +4 -0
- data/lib/arel_extensions/visitors/to_sql.rb +20 -0
- data/lib/arel_extensions/visitors.rb +8 -0
- data/lib/arel_extensions.rb +16 -0
- data/test/with_ar/all_agnostic_test.rb +249 -129
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +9 -19
data/README.md
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
# Arel Extensions
|
2
2
|
|
3
3
|

|
4
|
-
[](https://hakiri.io/github/Faveod/arel-extensions/master)
|
4
|
+
[](https://ci.appveyor.com/project/jdelporte/arel-extensions)
|
6
5
|

|
7
6
|
|
8
7
|
Gem: [](https://rubygems.org/gems/arel_extensions)
|
9
8
|
[](https://rubygems.org/gems/arel_extensions)
|
10
9
|
[](https://rubygems.org/gems/arel_extensions)
|
11
10
|
|
12
|
-
Arel Extensions adds shortcuts, fixes and new ORM mappings (
|
13
|
-
It aims to ensure pure
|
11
|
+
Arel Extensions adds shortcuts, fixes and new ORM mappings (Ruby to SQL) to Arel.
|
12
|
+
It aims to ensure pure Ruby syntax for most usual cases.
|
14
13
|
It allows to use more advanced SQL functions for any supported RDBMS.
|
15
14
|
|
16
15
|
|
@@ -37,7 +36,8 @@ It will add common SQL features in your DB to align ti with current routines. Te
|
|
37
36
|
|
38
37
|
## Examples
|
39
38
|
|
40
|
-
|
39
|
+
In the following examples
|
40
|
+
`t` is an `Arel::Table` for table `my_table` (i.e., `t = Arel::Table.new('my_table')`).
|
41
41
|
|
42
42
|
## Comparators
|
43
43
|
|
@@ -51,7 +51,7 @@ t is an Arel::Table for table my_table
|
|
51
51
|
# => my_table.nb > 42
|
52
52
|
```
|
53
53
|
|
54
|
-
Other operators
|
54
|
+
Other operators: <, >=, <=, =~
|
55
55
|
|
56
56
|
|
57
57
|
## Maths
|
@@ -74,7 +74,7 @@ With Arel Extensions:
|
|
74
74
|
# => SUM(my_table.nb) + 42
|
75
75
|
```
|
76
76
|
|
77
|
-
Other functions
|
77
|
+
Other functions: ABS, RAND, ROUND, FLOOR, CEIL, FORMAT
|
78
78
|
|
79
79
|
For Example:
|
80
80
|
```ruby
|
@@ -95,14 +95,29 @@ t[:price].format_number("%07.2f €","fr_FR")
|
|
95
95
|
# => TRIM(TRIM(TRIM(COALESCE(my_table.name, '')), '\t'), '\n') = ''
|
96
96
|
|
97
97
|
(t[:name] =~ /\A[a-d_]+/).to_sql
|
98
|
-
# => my_table.name REGEXP '
|
98
|
+
# => my_table.name REGEXP '^[a-d_]+'
|
99
99
|
```
|
100
100
|
|
101
|
-
|
101
|
+
The `replace` function supports string and regex patterns.
|
102
|
+
For instance
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
t[:email].replace('@', ' at ').replace('.', ' dot ').to_sql
|
106
|
+
# => REPLACE(REPLACE(`my_table`.`email`, '@', ' at '), '.', ' dot ')
|
107
|
+
```
|
108
|
+
|
109
|
+
Captures are supported when using regex patterns. The replace string may then reference the capture groups using `\1`, `\2`, etc. For instance
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
t[:email].replace(/^(.*)@(.*)$/, 'user: \1, host: \2').to_sql
|
113
|
+
# => REGEXP_REPLACE(`my_table`.`email`, '(?-mix:^(.*)@(.*)$)', 'user: \\1, host: \\2')
|
114
|
+
```
|
115
|
+
|
116
|
+
Other functions: SOUNDEX, LENGTH, REPLACE, LOCATE, SUBSTRING, TRIM
|
102
117
|
|
103
118
|
### String Array operations
|
104
119
|
|
105
|
-
|
120
|
+
`t[:list]` is a classical varchar containing a comma separated list (`"1,2,3,4"`).
|
106
121
|
|
107
122
|
```ruby
|
108
123
|
(t[:list] & 3).to_sql
|
@@ -229,15 +244,15 @@ t[:id].cast('char').to_sql
|
|
229
244
|
## Stored Procedures and User-defined functions
|
230
245
|
|
231
246
|
To optimize queries, some classical functions are defined in databases missing any alternative native functions.
|
232
|
-
Examples
|
233
|
-
- FIND_IN_SET
|
247
|
+
Examples:
|
248
|
+
- `FIND_IN_SET`
|
234
249
|
|
235
250
|
## BULK INSERT / UPSERT
|
236
251
|
|
237
252
|
Arel Extensions improves InsertManager by adding bulk_insert method, which allows to insert multiple rows in one insert.
|
238
253
|
|
239
254
|
|
240
|
-
```
|
255
|
+
```ruby
|
241
256
|
@cols = ['id', 'name', 'comments', 'created_at']
|
242
257
|
@data = [
|
243
258
|
[23, 'name1', "sdfdsfdsfsdf", '2016-01-01'],
|
@@ -293,6 +308,15 @@ User.connection.execute(insert_manager.to_sql)
|
|
293
308
|
<td class="ok">✔</td>
|
294
309
|
<td class="ok">✔</td>
|
295
310
|
</tr>
|
311
|
+
<tr>
|
312
|
+
<td class="tg-yw4l">POSIX FORMATTING<br>column.format_number("$ %7.2f","en_US")</td>
|
313
|
+
<td class="ok">✔</td>
|
314
|
+
<td class="ok">✔</td>
|
315
|
+
<td class="ok">✔</td>
|
316
|
+
<td class="ok">✔</td>
|
317
|
+
<td class="ok">✔</td>
|
318
|
+
<td class="ko">not implemented</td>
|
319
|
+
</tr>
|
296
320
|
<tr>
|
297
321
|
<td class="tg-yw4l">RAND<br>Arel.rand</td>
|
298
322
|
<td class="ok">✔</td>
|
@@ -321,23 +345,32 @@ User.connection.execute(insert_manager.to_sql)
|
|
321
345
|
<td class="ok">✔</td>
|
322
346
|
</tr>
|
323
347
|
<tr>
|
324
|
-
<
|
325
|
-
<td class="
|
348
|
+
<th class="tg-ffjm" rowspan="17"><div>String functions</div></th>
|
349
|
+
<td class="tg-yw4l">CONCAT<br>column + "string"</td>
|
326
350
|
<td class="ok">✔</td>
|
327
351
|
<td class="ok">✔</td>
|
352
|
+
<td class="tg-j6lv"> ||</td>
|
328
353
|
<td class="ok">✔</td>
|
354
|
+
<td class="tg-j6lv">+</td>
|
329
355
|
<td class="ok">✔</td>
|
330
|
-
<td class="ko">not implemented</td>
|
331
356
|
</tr>
|
332
357
|
<tr>
|
333
|
-
<
|
334
|
-
<td class="tg-yw4l">CONCAT<br>column + "string"</td>
|
358
|
+
<td class="tg-yw4l">FIND_IN_SET<br>column & ("l")</td>
|
335
359
|
<td class="ok">✔</td>
|
336
360
|
<td class="ok">✔</td>
|
337
|
-
<td class="tg-
|
361
|
+
<td class="tg-orpl">Ruby function</td>
|
362
|
+
<td class="ok">✔</td>
|
363
|
+
<td class="ok">✔</td>
|
364
|
+
<td class="ok">✔</td>
|
365
|
+
</tr>
|
366
|
+
<tr>
|
367
|
+
<td class="tg-yw4l">ILIKE (in Arel6)<br/>column.imatches('%pattern')</td>
|
368
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
338
369
|
<td class="ok">✔</td>
|
339
|
-
<td class="tg-j6lv">+</td>
|
340
370
|
<td class="ok">✔</td>
|
371
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
372
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
373
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
341
374
|
</tr>
|
342
375
|
<tr>
|
343
376
|
<td class="tg-yw4l">LENGTH<br>column.length</td>
|
@@ -358,30 +391,57 @@ User.connection.execute(insert_manager.to_sql)
|
|
358
391
|
<td class="ok">✔</td>
|
359
392
|
</tr>
|
360
393
|
<tr>
|
361
|
-
<td class="tg-yw4l">
|
362
|
-
<td class="ok">✔</td>
|
363
|
-
<td class="tg-j6lv">SUBSTR()</td>
|
364
|
-
<td class="tg-j6lv">SUBSTR()</td>
|
365
|
-
<td class="tg-j6lv">SUBSTR()</td>
|
394
|
+
<td class="tg-yw4l">Matching Accent/Case Insensitive<br>column.ai_imatches('blah')</td>
|
366
395
|
<td class="ok">✔</td>
|
396
|
+
<td class="tg-j6lv">unaccent required</td>
|
397
|
+
<td class="tg-j6lv">not supported</td>
|
367
398
|
<td class="ok">✔</td>
|
399
|
+
<td class="tg-j6lv">✔</td>
|
400
|
+
<td class="tg-j6lv">?</td>
|
368
401
|
</tr>
|
369
402
|
<tr>
|
370
|
-
<td class="tg-yw4l">
|
371
|
-
<td class="ok"
|
372
|
-
<td class="
|
373
|
-
<td class="tg-
|
403
|
+
<td class="tg-yw4l">Matching Accent Insensitive<br>column.ai_matches('blah')</td>
|
404
|
+
<td class="ok">not supported</td>
|
405
|
+
<td class="tg-j6lv">not supported</td>
|
406
|
+
<td class="tg-j6lv">not supported</td>
|
407
|
+
<td class="ok">not supported</td>
|
408
|
+
<td class="tg-j6lv">✔</td>
|
409
|
+
<td class="tg-j6lv">?</td>
|
410
|
+
</tr>
|
411
|
+
<tr>
|
412
|
+
<td class="tg-yw4l">Matching Case Insensitive<br>column.imatches('blah')</td>
|
413
|
+
<td class="ok">not supported</td>
|
414
|
+
<td class="tg-j6lv">✔</td>
|
415
|
+
<td class="tg-j6lv">✔</td>
|
374
416
|
<td class="ok">✔</td>
|
417
|
+
<td class="tg-j6lv">✔</td>
|
418
|
+
<td class="tg-j6lv">?</td>
|
419
|
+
</tr>
|
420
|
+
<tr>
|
421
|
+
<td class="tg-yw4l">Matching Accent/Case Sensitive<br>column.smatches('blah')</td>
|
375
422
|
<td class="ok">✔</td>
|
423
|
+
<td class="tg-j6lv">✔</td>
|
424
|
+
<td class="tg-j6lv">not supported</td>
|
376
425
|
<td class="ok">✔</td>
|
426
|
+
<td class="tg-j6lv">✔</td>
|
427
|
+
<td class="tg-j6lv">?</td>
|
377
428
|
</tr>
|
378
429
|
<tr>
|
379
|
-
<td class="tg-yw4l">
|
430
|
+
<td class="tg-yw4l">NOT_REGEXP<br>column != "pattern"</td>
|
380
431
|
<td class="ok">✔</td>
|
381
|
-
<td class="
|
432
|
+
<td class="ok">✔<br></td>
|
433
|
+
<td class="tg-3oug">require pcre.so</td>
|
434
|
+
<td class="tg-j6lv">NOT REGEXP_LIKE </td>
|
435
|
+
<td class="tg-j6lv">NOT LIKE</td>
|
382
436
|
<td class="ok">✔</td>
|
437
|
+
</tr>
|
438
|
+
<tr>
|
439
|
+
<td class="tg-yw4l">REGEXP<br>column =~ "pattern"<br></td>
|
383
440
|
<td class="ok">✔</td>
|
384
441
|
<td class="ok">✔</td>
|
442
|
+
<td class="tg-3oug">require pcre.so</td>
|
443
|
+
<td class="tg-j6lv">REGEXP_LIKE</td>
|
444
|
+
<td class="tg-j6lv">LIKE</td>
|
385
445
|
<td class="ok">✔</td>
|
386
446
|
</tr>
|
387
447
|
<tr>
|
@@ -394,31 +454,31 @@ User.connection.execute(insert_manager.to_sql)
|
|
394
454
|
<td class="ok">✔</td>
|
395
455
|
</tr>
|
396
456
|
<tr>
|
397
|
-
<td class="tg-yw4l">
|
457
|
+
<td class="tg-yw4l">REPLACE<br>column.replace(/re/,"X")</td>
|
458
|
+
<td class="ok">✔</td>
|
459
|
+
<td class="ok">✔</td>
|
460
|
+
<td class="ok">✔</td>
|
398
461
|
<td class="ok">✔</td>
|
399
462
|
<td class="ok">✔</td>
|
400
|
-
<td class="tg-3oug">require pcre.so</td>
|
401
|
-
<td class="tg-j6lv">REGEXP_LIKE</td>
|
402
|
-
<td class="tg-j6lv">LIKE</td>
|
403
463
|
<td class="ok">✔</td>
|
404
464
|
</tr>
|
405
465
|
<tr>
|
406
|
-
<td class="tg-yw4l">
|
466
|
+
<td class="tg-yw4l">SOUNDEX<br>column.soundex</td>
|
467
|
+
<td class="ok">✔</td>
|
468
|
+
<td class="tg-3oug">require fuzzystrmatch</td>
|
469
|
+
<td class="ok">✔</td>
|
470
|
+
<td class="ok">✔</td>
|
407
471
|
<td class="ok">✔</td>
|
408
|
-
<td class="ok">✔<br></td>
|
409
|
-
<td class="tg-3oug">require pcre.so</td>
|
410
|
-
<td class="tg-j6lv">NOT REGEXP_LIKE </td>
|
411
|
-
<td class="tg-j6lv">NOT LIKE</td>
|
412
472
|
<td class="ok">✔</td>
|
413
473
|
</tr>
|
414
474
|
<tr>
|
415
|
-
<td class="tg-yw4l">
|
416
|
-
<td class="
|
475
|
+
<td class="tg-yw4l">SUBSTRING<br/>column[1..2]<br/>column.substring(1)<br/>column.substring(1, 1)</td>
|
476
|
+
<td class="ok">✔</td>
|
477
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
478
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
479
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
417
480
|
<td class="ok">✔</td>
|
418
481
|
<td class="ok">✔</td>
|
419
|
-
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
420
|
-
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
421
|
-
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
422
482
|
</tr>
|
423
483
|
<tr>
|
424
484
|
<td class="tg-yw4l">TRIM (leading)<br>column.trim("LEADING","M")</td>
|
@@ -447,43 +507,6 @@ User.connection.execute(insert_manager.to_sql)
|
|
447
507
|
<td class="tg-j6lv">LTRIM(RTRIM())</td>
|
448
508
|
<td class="tg-j6lv">TRIM()</td>
|
449
509
|
</tr>
|
450
|
-
<tr>
|
451
|
-
<td class="tg-yw4l">Matching Accent/Case Insensitive<br>column.ai_imatches('blah')</td>
|
452
|
-
<td class="ok">✔</td>
|
453
|
-
<td class="tg-j6lv">unaccent required</td>
|
454
|
-
<td class="tg-j6lv">not supported</td>
|
455
|
-
<td class="ok">✔</td>
|
456
|
-
<td class="tg-j6lv">✔</td>
|
457
|
-
<td class="tg-j6lv">?</td>
|
458
|
-
</tr>
|
459
|
-
<tr>
|
460
|
-
<td class="tg-yw4l">Matching Accent Insensitive<br>column.ai_matches('blah')</td>
|
461
|
-
<td class="ok">not supported</td>
|
462
|
-
<td class="tg-j6lv">not supported</td>
|
463
|
-
<td class="tg-j6lv">not supported</td>
|
464
|
-
<td class="ok">not supported</td>
|
465
|
-
<td class="tg-j6lv">✔</td>
|
466
|
-
<td class="tg-j6lv">?</td>
|
467
|
-
</tr>
|
468
|
-
<tr>
|
469
|
-
<td class="tg-yw4l">Matching Case Insensitive<br>column.imatches('blah')</td>
|
470
|
-
<td class="ok">not supported</td>
|
471
|
-
<td class="tg-j6lv">✔</td>
|
472
|
-
<td class="tg-j6lv">✔</td>
|
473
|
-
<td class="ok">✔</td>
|
474
|
-
<td class="tg-j6lv">✔</td>
|
475
|
-
<td class="tg-j6lv">?</td>
|
476
|
-
</tr>
|
477
|
-
<tr>
|
478
|
-
<td class="tg-yw4l">Matching Accent/Case Sensitive<br>column.smatches('blah')</td>
|
479
|
-
<td class="ok">✔</td>
|
480
|
-
<td class="tg-j6lv">✔</td>
|
481
|
-
<td class="tg-j6lv">not supported</td>
|
482
|
-
<td class="ok">✔</td>
|
483
|
-
<td class="tg-j6lv">✔</td>
|
484
|
-
<td class="tg-j6lv">?</td>
|
485
|
-
</tr>
|
486
|
-
|
487
510
|
<tr>
|
488
511
|
<th class="tg-4rp9" rowspan="6"><div>Date functions</div></th>
|
489
512
|
<td class="tg-yw4l">DATEADD<br>column + 2.year<br></td>
|
@@ -540,7 +563,16 @@ User.connection.execute(insert_manager.to_sql)
|
|
540
563
|
<td class="ok">✔</td>
|
541
564
|
</tr>
|
542
565
|
<tr>
|
543
|
-
<th class="tg-72dn" rowspan="
|
566
|
+
<th class="tg-72dn" rowspan="13"><div>Comparators functions</div></th>
|
567
|
+
<td class="tg-yw4l">BLANK<br>column.blank<br></td>
|
568
|
+
<td class="ok">✔</td>
|
569
|
+
<td class="ok">✔</td>
|
570
|
+
<td class="ok">✔</td>
|
571
|
+
<td class="ok">✔</td>
|
572
|
+
<td class="ok">✔</td>
|
573
|
+
<td class="ok">✔</td>
|
574
|
+
</tr>
|
575
|
+
<tr>
|
544
576
|
<td class="tg-yw4l">COALESCE<br>column.coalesce(var)</td>
|
545
577
|
<td class="ok">✔</td>
|
546
578
|
<td class="ok">✔</td>
|
@@ -549,6 +581,24 @@ User.connection.execute(insert_manager.to_sql)
|
|
549
581
|
<td class="ok">✔</td>
|
550
582
|
<td class="ok">✔</td>
|
551
583
|
</tr>
|
584
|
+
<tr>
|
585
|
+
<td class="tg-yw4l">COALESCE_BLANK<br>column.coalesce_blank(var)</td>
|
586
|
+
<td class="ok">✔</td>
|
587
|
+
<td class="ok">✔</td>
|
588
|
+
<td class="ok">✔</td>
|
589
|
+
<td class="ok">✔</td>
|
590
|
+
<td class="ok">✔</td>
|
591
|
+
<td class="ok">✔</td>
|
592
|
+
</tr>
|
593
|
+
<tr>
|
594
|
+
<td class="tg-yw4l">IF_PRESENT</td>
|
595
|
+
<td class="ok">✔</td>
|
596
|
+
<td class="ok">✔</td>
|
597
|
+
<td class="ok">✔</td>
|
598
|
+
<td class="ok">✔</td>
|
599
|
+
<td class="ok">✔</td>
|
600
|
+
<td class="ok">✔</td>
|
601
|
+
</tr>
|
552
602
|
<tr>
|
553
603
|
<td class="tg-yw4l">ISNULL<br>column.isnull()</td>
|
554
604
|
<td class="tg-j6lv">IFNULL()</td>
|
@@ -558,6 +608,24 @@ User.connection.execute(insert_manager.to_sql)
|
|
558
608
|
<td class="ok">✔</td>
|
559
609
|
<td class="ok">✔</td>
|
560
610
|
</tr>
|
611
|
+
<tr>
|
612
|
+
<td class="tg-yw4l">NOT_BLANK<br>column.not_blank<br></td>
|
613
|
+
<td class="ok">✔</td>
|
614
|
+
<td class="ok">✔</td>
|
615
|
+
<td class="ok">✔</td>
|
616
|
+
<td class="ok">✔</td>
|
617
|
+
<td class="ok">✔</td>
|
618
|
+
<td class="ok">✔</td>
|
619
|
+
</tr>
|
620
|
+
<tr>
|
621
|
+
<td class="tg-yw4l">PRESENT<br>column.present<br>alias to NOT_BLANK<br></td>
|
622
|
+
<td class="ok">✔</td>
|
623
|
+
<td class="ok">✔</td>
|
624
|
+
<td class="ok">✔</td>
|
625
|
+
<td class="ok">✔</td>
|
626
|
+
<td class="ok">✔</td>
|
627
|
+
<td class="ok">✔</td>
|
628
|
+
</tr>
|
561
629
|
<tr>
|
562
630
|
<td class="tg-yw4l">==<br>column == integer</td>
|
563
631
|
<td class="ok">✔</td>
|
data/appveyor.yml
CHANGED
@@ -7,6 +7,15 @@ cache:
|
|
7
7
|
|
8
8
|
environment:
|
9
9
|
matrix:
|
10
|
+
- RUBY_VERSION: 25-x64
|
11
|
+
RAILS: 4_2
|
12
|
+
SQL: MSSQL$SQL2012SP1
|
13
|
+
- RUBY_VERSION: 25-x64
|
14
|
+
RAILS: 4_2
|
15
|
+
SQL: MSSQL$SQL2014
|
16
|
+
- RUBY_VERSION: 25-x64
|
17
|
+
RAILS: 4_2
|
18
|
+
SQL: MSSQL$SQL2016
|
10
19
|
- RUBY_VERSION: 25-x64
|
11
20
|
RAILS: 5_2
|
12
21
|
SQL: MSSQL$SQL2012SP1
|
data/arel_extensions.gemspec
CHANGED
@@ -3,6 +3,13 @@ source 'https://rubygems.org'
|
|
3
3
|
gem 'arel', '~> 6.0'
|
4
4
|
|
5
5
|
group :development, :test do
|
6
|
+
# We need to explicitly include bigdecimal for ruby 2.7 .
|
7
|
+
# See https://github.com/ruby/bigdecimal for details.
|
8
|
+
rb_version = Gem::Version.new(RUBY_VERSION)
|
9
|
+
if Gem::Version.new('2.7') <= rb_version && rb_version < Gem::Version.new('2.8')
|
10
|
+
gem 'bigdecimal', '~> 1.3.5', platforms: %i[mri mingw x64_mingw mswin]
|
11
|
+
end
|
12
|
+
|
6
13
|
gem 'activesupport', '~> 4.0'
|
7
14
|
gem 'activemodel', '~> 4.0'
|
8
15
|
gem 'activerecord', '~> 4.0'
|
@@ -11,15 +18,17 @@ group :development, :test do
|
|
11
18
|
gem 'mysql2', '0.4.10', platforms: %i[mri mswin mingw]
|
12
19
|
gem 'pg', '< 1.0.0', platforms: %i[mri mingw]
|
13
20
|
|
14
|
-
gem 'tiny_tds', platforms: %i[mri mingw mswin]
|
15
|
-
gem 'activerecord-sqlserver-adapter', '~> 4.2.0', platforms: %i[mri mingw mswin]
|
21
|
+
gem 'tiny_tds', platforms: %i[mri mingw x64_mingw mswin]
|
22
|
+
gem 'activerecord-sqlserver-adapter', '~> 4.2.0', platforms: %i[mri mingw x64_mingw mswin]
|
16
23
|
|
17
24
|
gem 'ruby-oci8', platforms: %i[mri mswin mingw] if ENV.has_key? 'ORACLE_HOME'
|
18
25
|
gem 'activerecord-oracle_enhanced-adapter', '~> 1.6.0' if ENV.has_key? 'ORACLE_HOME'
|
19
26
|
|
20
27
|
# for JRuby
|
21
28
|
gem 'activerecord-jdbc-adapter', '~> 1.3', platforms: :jruby
|
22
|
-
gem 'jdbc-sqlite3', platforms: :jruby
|
29
|
+
gem 'jdbc-sqlite3', '~> 3.28', platforms: :jruby
|
30
|
+
gem 'jdbc-postgres', '~> 42.2', platforms: :jruby
|
31
|
+
gem 'jdbc-mysql', '~> 5.1', platforms: :jruby
|
23
32
|
gem 'activerecord-jdbcsqlite3-adapter', platforms: :jruby
|
24
33
|
gem 'activerecord-jdbcmysql-adapter', platforms: :jruby
|
25
34
|
gem 'activerecord-jdbcpostgresql-adapter', platforms: :jruby
|
File without changes
|
data/gemfiles/rails6_1.gemfile
CHANGED
@@ -9,7 +9,7 @@ group :development, :test do
|
|
9
9
|
gem 'activerecord', '~> 6.1.0'
|
10
10
|
|
11
11
|
gem 'sqlite3', '~> 1.4', platforms: [:mri]
|
12
|
-
gem 'mysql2', '0.5
|
12
|
+
gem 'mysql2', '~>0.5', platforms: [:mri]
|
13
13
|
gem 'pg', '~> 1.1', platforms: [:mri]
|
14
14
|
|
15
15
|
gem 'tiny_tds', platforms: %i[mri mingw x64_mingw mswin]
|
data/gemfiles/rails7.gemfile
CHANGED
@@ -9,7 +9,7 @@ group :development, :test do
|
|
9
9
|
gem 'activerecord', '~> 7.0.1'
|
10
10
|
|
11
11
|
gem 'sqlite3', '~> 1.4', platforms: [:mri]
|
12
|
-
gem 'mysql2', '0.5
|
12
|
+
gem 'mysql2', '~>0.5', platforms: [:mri]
|
13
13
|
gem 'pg', '~> 1.1', platforms: [:mri]
|
14
14
|
|
15
15
|
gem 'tiny_tds', platforms: %i[mri mingw x64_mingw mswin]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'arel_extensions/nodes/format'
|
2
|
+
require 'arel_extensions/nodes/formatted_date'
|
2
3
|
require 'arel_extensions/nodes/duration'
|
3
4
|
require 'arel_extensions/nodes/wday'
|
4
5
|
|
@@ -43,5 +44,9 @@ module ArelExtensions
|
|
43
44
|
def format(tpl, time_zone = nil)
|
44
45
|
ArelExtensions::Nodes::Format.new [self, tpl, time_zone]
|
45
46
|
end
|
47
|
+
|
48
|
+
def format_date(tpl, time_zone = nil)
|
49
|
+
ArelExtensions::Nodes::FormattedDate.new [self, tpl, time_zone]
|
50
|
+
end
|
46
51
|
end
|
47
52
|
end
|
@@ -35,12 +35,13 @@ module ArelExtensions
|
|
35
35
|
include Arel::Predications
|
36
36
|
include Arel::OrderPredications
|
37
37
|
include ArelExtensions::Aliases
|
38
|
-
include ArelExtensions::Math
|
39
38
|
include ArelExtensions::Comparators
|
40
|
-
include ArelExtensions::
|
39
|
+
include ArelExtensions::DateDuration
|
40
|
+
include ArelExtensions::Math
|
41
41
|
include ArelExtensions::MathFunctions
|
42
|
-
include ArelExtensions::StringFunctions
|
43
42
|
include ArelExtensions::NullFunctions
|
43
|
+
include ArelExtensions::Predications
|
44
|
+
include ArelExtensions::StringFunctions
|
44
45
|
|
45
46
|
def return_type
|
46
47
|
obj = if @conditions.length > 0
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module ArelExtensions
|
4
|
+
module Nodes
|
5
|
+
class FormattedDate < Function
|
6
|
+
RETURN_TYPE = :string
|
7
|
+
|
8
|
+
attr_accessor :col_type, :iso_format, :time_zone
|
9
|
+
|
10
|
+
def initialize expr
|
11
|
+
col = expr[0]
|
12
|
+
@iso_format = convert_format(expr[1])
|
13
|
+
@time_zone = expr[2]
|
14
|
+
@col_type = type_of_attribute(col)
|
15
|
+
super [col, convert_to_string_node(@iso_format)]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Address portability issues with some of the formats.
|
21
|
+
def convert_format(fmt)
|
22
|
+
s = StringScanner.new fmt
|
23
|
+
res = StringIO.new
|
24
|
+
while !s.eos?
|
25
|
+
res <<
|
26
|
+
case
|
27
|
+
when s.scan(/%D/) then '%m/%d/%y'
|
28
|
+
when s.scan(/%F/) then '%Y-%m-%d'
|
29
|
+
when s.scan(/%R/) then '%H:%M'
|
30
|
+
when s.scan(/%r/) then '%I:%M:%S %p'
|
31
|
+
when s.scan(/%T/) then '%H:%M:%S'
|
32
|
+
when s.scan(/%v/) then '%e-%b-%Y'
|
33
|
+
|
34
|
+
when s.scan(/[^%]+/) then s.matched
|
35
|
+
when s.scan(/./) then s.matched
|
36
|
+
end
|
37
|
+
end
|
38
|
+
res.string
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# The following is a patch to activerecord when it doesn't
|
2
|
+
# have RollUp defined, i.e. for rails < 5.2
|
3
|
+
|
4
|
+
begin
|
5
|
+
Arel::Nodes.const_get('RollUp')
|
6
|
+
rescue NameError => e
|
7
|
+
module Arel
|
8
|
+
module Nodes
|
9
|
+
class RollUp < Arel::Nodes::Unary
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Arel
|
15
|
+
module Visitors
|
16
|
+
class PostgreSQL
|
17
|
+
# Utilized by GroupingSet, Cube & RollUp visitors to
|
18
|
+
# handle grouping aggregation semantics
|
19
|
+
def grouping_array_or_grouping_element(o, collector)
|
20
|
+
if o.expr.is_a? Array
|
21
|
+
collector << "( "
|
22
|
+
visit o.expr, collector
|
23
|
+
collector << " )"
|
24
|
+
else
|
25
|
+
visit o.expr, collector
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_Arel_Nodes_RollUp(o, collector)
|
30
|
+
collector << "ROLLUP"
|
31
|
+
grouping_array_or_grouping_element o, collector
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -3,6 +3,12 @@ require 'arel_extensions/nodes/is_null'
|
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
5
|
module NullFunctions
|
6
|
+
|
7
|
+
# if_present returns nil if the the value is nil or blank
|
8
|
+
def if_present
|
9
|
+
Arel.when(self.cast(:string).present).then(self)
|
10
|
+
end
|
11
|
+
|
6
12
|
# ISNULL function lets you return an alternative value when an expression is NULL.
|
7
13
|
def is_null
|
8
14
|
ArelExtensions::Nodes::IsNull.new [self]
|
@@ -19,5 +25,15 @@ module ArelExtensions
|
|
19
25
|
args.unshift(self)
|
20
26
|
ArelExtensions::Nodes::Coalesce.new args
|
21
27
|
end
|
28
|
+
|
29
|
+
def coalesce_blank *args
|
30
|
+
res = Arel.when(self.cast(:string).present).then(self)
|
31
|
+
args[0...-1].each do |a|
|
32
|
+
val = a.is_a?(Arel::Nodes::Node) ? a : Arel.quoted(a)
|
33
|
+
res = res.when(val.present).then(a)
|
34
|
+
end
|
35
|
+
res = res.else(args[-1])
|
36
|
+
res
|
37
|
+
end
|
22
38
|
end
|
23
39
|
end
|