arel_extensions 2.1.5 → 2.1.6
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 +141 -153
- data/NEWS.md +15 -0
- data/README.md +119 -76
- 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/gemspecs/arel_extensions-v1.gemspec +0 -1
- data/gemspecs/arel_extensions-v2.gemspec +0 -1
- data/lib/arel_extensions/nodes/case.rb +4 -3
- 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 +93 -0
- data/lib/arel_extensions/visitors/mysql.rb +63 -1
- data/lib/arel_extensions/visitors/oracle.rb +17 -0
- data/lib/arel_extensions/visitors.rb +8 -0
- data/lib/arel_extensions.rb +16 -0
- data/test/with_ar/all_agnostic_test.rb +110 -10
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +7 -18
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
|
|
@@ -293,6 +292,15 @@ User.connection.execute(insert_manager.to_sql)
|
|
293
292
|
<td class="ok">✔</td>
|
294
293
|
<td class="ok">✔</td>
|
295
294
|
</tr>
|
295
|
+
<tr>
|
296
|
+
<td class="tg-yw4l">POSIX FORMATTING<br>column.format_number("$ %7.2f","en_US")</td>
|
297
|
+
<td class="ok">✔</td>
|
298
|
+
<td class="ok">✔</td>
|
299
|
+
<td class="ok">✔</td>
|
300
|
+
<td class="ok">✔</td>
|
301
|
+
<td class="ok">✔</td>
|
302
|
+
<td class="ko">not implemented</td>
|
303
|
+
</tr>
|
296
304
|
<tr>
|
297
305
|
<td class="tg-yw4l">RAND<br>Arel.rand</td>
|
298
306
|
<td class="ok">✔</td>
|
@@ -321,24 +329,33 @@ User.connection.execute(insert_manager.to_sql)
|
|
321
329
|
<td class="ok">✔</td>
|
322
330
|
</tr>
|
323
331
|
<tr>
|
324
|
-
<
|
325
|
-
<td class="
|
332
|
+
<th class="tg-ffjm" rowspan="17"><div>String functions</div></th>
|
333
|
+
<td class="tg-yw4l">CONCAT<br>column + "string"</td>
|
326
334
|
<td class="ok">✔</td>
|
327
335
|
<td class="ok">✔</td>
|
336
|
+
<td class="tg-j6lv"> ||</td>
|
328
337
|
<td class="ok">✔</td>
|
338
|
+
<td class="tg-j6lv">+</td>
|
329
339
|
<td class="ok">✔</td>
|
330
|
-
<td class="ko">not implemented</td>
|
331
340
|
</tr>
|
332
341
|
<tr>
|
333
|
-
<
|
334
|
-
<td class="tg-yw4l">CONCAT<br>column + "string"</td>
|
342
|
+
<td class="tg-yw4l">FIND_IN_SET<br>column & ("l")</td>
|
335
343
|
<td class="ok">✔</td>
|
336
344
|
<td class="ok">✔</td>
|
337
|
-
<td class="tg-
|
345
|
+
<td class="tg-orpl">Ruby function</td>
|
346
|
+
<td class="ok">✔</td>
|
338
347
|
<td class="ok">✔</td>
|
339
|
-
<td class="tg-j6lv">+</td>
|
340
348
|
<td class="ok">✔</td>
|
341
349
|
</tr>
|
350
|
+
<tr>
|
351
|
+
<td class="tg-yw4l">ILIKE (in Arel6)<br/>column.imatches('%pattern')</td>
|
352
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
353
|
+
<td class="ok">✔</td>
|
354
|
+
<td class="ok">✔</td>
|
355
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
356
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
357
|
+
<td class="tg-j6lv">LOWER() LIKE LOWER()</td>
|
358
|
+
</tr>
|
342
359
|
<tr>
|
343
360
|
<td class="tg-yw4l">LENGTH<br>column.length</td>
|
344
361
|
<td class="ok">✔</td>
|
@@ -358,30 +375,57 @@ User.connection.execute(insert_manager.to_sql)
|
|
358
375
|
<td class="ok">✔</td>
|
359
376
|
</tr>
|
360
377
|
<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>
|
378
|
+
<td class="tg-yw4l">Matching Accent/Case Insensitive<br>column.ai_imatches('blah')</td>
|
366
379
|
<td class="ok">✔</td>
|
380
|
+
<td class="tg-j6lv">unaccent required</td>
|
381
|
+
<td class="tg-j6lv">not supported</td>
|
367
382
|
<td class="ok">✔</td>
|
383
|
+
<td class="tg-j6lv">✔</td>
|
384
|
+
<td class="tg-j6lv">?</td>
|
368
385
|
</tr>
|
369
386
|
<tr>
|
370
|
-
<td class="tg-yw4l">
|
371
|
-
<td class="ok"
|
372
|
-
<td class="
|
373
|
-
<td class="tg-
|
387
|
+
<td class="tg-yw4l">Matching Accent Insensitive<br>column.ai_matches('blah')</td>
|
388
|
+
<td class="ok">not supported</td>
|
389
|
+
<td class="tg-j6lv">not supported</td>
|
390
|
+
<td class="tg-j6lv">not supported</td>
|
391
|
+
<td class="ok">not supported</td>
|
392
|
+
<td class="tg-j6lv">✔</td>
|
393
|
+
<td class="tg-j6lv">?</td>
|
394
|
+
</tr>
|
395
|
+
<tr>
|
396
|
+
<td class="tg-yw4l">Matching Case Insensitive<br>column.imatches('blah')</td>
|
397
|
+
<td class="ok">not supported</td>
|
398
|
+
<td class="tg-j6lv">✔</td>
|
399
|
+
<td class="tg-j6lv">✔</td>
|
374
400
|
<td class="ok">✔</td>
|
401
|
+
<td class="tg-j6lv">✔</td>
|
402
|
+
<td class="tg-j6lv">?</td>
|
403
|
+
</tr>
|
404
|
+
<tr>
|
405
|
+
<td class="tg-yw4l">Matching Accent/Case Sensitive<br>column.smatches('blah')</td>
|
375
406
|
<td class="ok">✔</td>
|
407
|
+
<td class="tg-j6lv">✔</td>
|
408
|
+
<td class="tg-j6lv">not supported</td>
|
376
409
|
<td class="ok">✔</td>
|
410
|
+
<td class="tg-j6lv">✔</td>
|
411
|
+
<td class="tg-j6lv">?</td>
|
377
412
|
</tr>
|
378
413
|
<tr>
|
379
|
-
<td class="tg-yw4l">
|
414
|
+
<td class="tg-yw4l">NOT_REGEXP<br>column != "pattern"</td>
|
380
415
|
<td class="ok">✔</td>
|
381
|
-
<td class="
|
416
|
+
<td class="ok">✔<br></td>
|
417
|
+
<td class="tg-3oug">require pcre.so</td>
|
418
|
+
<td class="tg-j6lv">NOT REGEXP_LIKE </td>
|
419
|
+
<td class="tg-j6lv">NOT LIKE</td>
|
382
420
|
<td class="ok">✔</td>
|
421
|
+
</tr>
|
422
|
+
<tr>
|
423
|
+
<td class="tg-yw4l">REGEXP<br>column =~ "pattern"<br></td>
|
383
424
|
<td class="ok">✔</td>
|
384
425
|
<td class="ok">✔</td>
|
426
|
+
<td class="tg-3oug">require pcre.so</td>
|
427
|
+
<td class="tg-j6lv">REGEXP_LIKE</td>
|
428
|
+
<td class="tg-j6lv">LIKE</td>
|
385
429
|
<td class="ok">✔</td>
|
386
430
|
</tr>
|
387
431
|
<tr>
|
@@ -394,31 +438,22 @@ User.connection.execute(insert_manager.to_sql)
|
|
394
438
|
<td class="ok">✔</td>
|
395
439
|
</tr>
|
396
440
|
<tr>
|
397
|
-
<td class="tg-yw4l">
|
441
|
+
<td class="tg-yw4l">SOUNDEX<br>column.soundex</td>
|
398
442
|
<td class="ok">✔</td>
|
443
|
+
<td class="tg-3oug">require fuzzystrmatch</td>
|
399
444
|
<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
445
|
<td class="ok">✔</td>
|
404
|
-
</tr>
|
405
|
-
<tr>
|
406
|
-
<td class="tg-yw4l">NOT_REGEXP<br>column != "pattern"</td>
|
407
446
|
<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
447
|
<td class="ok">✔</td>
|
413
448
|
</tr>
|
414
449
|
<tr>
|
415
|
-
<td class="tg-yw4l">
|
416
|
-
<td class="
|
450
|
+
<td class="tg-yw4l">SUBSTRING<br/>column[1..2]<br/>column.substring(1)<br/>column.substring(1, 1)</td>
|
451
|
+
<td class="ok">✔</td>
|
452
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
453
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
454
|
+
<td class="tg-j6lv">SUBSTR()</td>
|
417
455
|
<td class="ok">✔</td>
|
418
456
|
<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
457
|
</tr>
|
423
458
|
<tr>
|
424
459
|
<td class="tg-yw4l">TRIM (leading)<br>column.trim("LEADING","M")</td>
|
@@ -447,43 +482,6 @@ User.connection.execute(insert_manager.to_sql)
|
|
447
482
|
<td class="tg-j6lv">LTRIM(RTRIM())</td>
|
448
483
|
<td class="tg-j6lv">TRIM()</td>
|
449
484
|
</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
485
|
<tr>
|
488
486
|
<th class="tg-4rp9" rowspan="6"><div>Date functions</div></th>
|
489
487
|
<td class="tg-yw4l">DATEADD<br>column + 2.year<br></td>
|
@@ -540,7 +538,16 @@ User.connection.execute(insert_manager.to_sql)
|
|
540
538
|
<td class="ok">✔</td>
|
541
539
|
</tr>
|
542
540
|
<tr>
|
543
|
-
<th class="tg-72dn" rowspan="
|
541
|
+
<th class="tg-72dn" rowspan="13"><div>Comparators functions</div></th>
|
542
|
+
<td class="tg-yw4l">BLANK<br>column.blank<br></td>
|
543
|
+
<td class="ok">✔</td>
|
544
|
+
<td class="ok">✔</td>
|
545
|
+
<td class="ok">✔</td>
|
546
|
+
<td class="ok">✔</td>
|
547
|
+
<td class="ok">✔</td>
|
548
|
+
<td class="ok">✔</td>
|
549
|
+
</tr>
|
550
|
+
<tr>
|
544
551
|
<td class="tg-yw4l">COALESCE<br>column.coalesce(var)</td>
|
545
552
|
<td class="ok">✔</td>
|
546
553
|
<td class="ok">✔</td>
|
@@ -549,6 +556,24 @@ User.connection.execute(insert_manager.to_sql)
|
|
549
556
|
<td class="ok">✔</td>
|
550
557
|
<td class="ok">✔</td>
|
551
558
|
</tr>
|
559
|
+
<tr>
|
560
|
+
<td class="tg-yw4l">COALESCE_BLANK<br>column.coalesce_blank(var)</td>
|
561
|
+
<td class="ok">✔</td>
|
562
|
+
<td class="ok">✔</td>
|
563
|
+
<td class="ok">✔</td>
|
564
|
+
<td class="ok">✔</td>
|
565
|
+
<td class="ok">✔</td>
|
566
|
+
<td class="ok">✔</td>
|
567
|
+
</tr>
|
568
|
+
<tr>
|
569
|
+
<td class="tg-yw4l">IF_PRESENT</td>
|
570
|
+
<td class="ok">✔</td>
|
571
|
+
<td class="ok">✔</td>
|
572
|
+
<td class="ok">✔</td>
|
573
|
+
<td class="ok">✔</td>
|
574
|
+
<td class="ok">✔</td>
|
575
|
+
<td class="ok">✔</td>
|
576
|
+
</tr>
|
552
577
|
<tr>
|
553
578
|
<td class="tg-yw4l">ISNULL<br>column.isnull()</td>
|
554
579
|
<td class="tg-j6lv">IFNULL()</td>
|
@@ -558,6 +583,24 @@ User.connection.execute(insert_manager.to_sql)
|
|
558
583
|
<td class="ok">✔</td>
|
559
584
|
<td class="ok">✔</td>
|
560
585
|
</tr>
|
586
|
+
<tr>
|
587
|
+
<td class="tg-yw4l">NOT_BLANK<br>column.not_blank<br></td>
|
588
|
+
<td class="ok">✔</td>
|
589
|
+
<td class="ok">✔</td>
|
590
|
+
<td class="ok">✔</td>
|
591
|
+
<td class="ok">✔</td>
|
592
|
+
<td class="ok">✔</td>
|
593
|
+
<td class="ok">✔</td>
|
594
|
+
</tr>
|
595
|
+
<tr>
|
596
|
+
<td class="tg-yw4l">PRESENT<br>column.present<br>alias to NOT_BLANK<br></td>
|
597
|
+
<td class="ok">✔</td>
|
598
|
+
<td class="ok">✔</td>
|
599
|
+
<td class="ok">✔</td>
|
600
|
+
<td class="ok">✔</td>
|
601
|
+
<td class="ok">✔</td>
|
602
|
+
<td class="ok">✔</td>
|
603
|
+
</tr>
|
561
604
|
<tr>
|
562
605
|
<td class="tg-yw4l">==<br>column == integer</td>
|
563
606
|
<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
|
@@ -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,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
|
@@ -49,6 +49,82 @@ module ArelExtensions
|
|
49
49
|
'YYYY-MM-DDTHH:MM:SS:MMM' => 126
|
50
50
|
}.freeze
|
51
51
|
|
52
|
+
# Quoting in JRuby + AR < 5 requires special handling for MSSQL.
|
53
|
+
#
|
54
|
+
# It relied on @connection.quote, which in turn relied on column type for
|
55
|
+
# quoting. We need only to rely on the value type.
|
56
|
+
#
|
57
|
+
# It didn't handle numbers correctly: `quote(1, nil)` translated into
|
58
|
+
# `N'1'` which we don't want.
|
59
|
+
#
|
60
|
+
# The following is adapted from activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
|
61
|
+
#
|
62
|
+
if RUBY_PLATFORM == 'java' && ActiveRecord::VERSION::MAJOR < 5
|
63
|
+
def quote_string(s)
|
64
|
+
s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
65
|
+
end
|
66
|
+
|
67
|
+
def quoted_binary(value) # :nodoc:
|
68
|
+
"'#{quote_string(value.to_s)}'"
|
69
|
+
end
|
70
|
+
|
71
|
+
def quoted_date(value)
|
72
|
+
if value.acts_like?(:time)
|
73
|
+
if ActiveRecord::Base.default_timezone == :utc
|
74
|
+
value = value.getutc if value.respond_to?(:getutc) && !value.utc?
|
75
|
+
else
|
76
|
+
value = value.getlocal if value.respond_to?(:getlocal)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
result = value.to_s(:db)
|
81
|
+
if value.respond_to?(:usec) && value.usec > 0
|
82
|
+
result << '.' << sprintf('%06d', value.usec)
|
83
|
+
else
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def quoted_true
|
89
|
+
'TRUE'
|
90
|
+
end
|
91
|
+
|
92
|
+
def quoted_false
|
93
|
+
'FALSE'
|
94
|
+
end
|
95
|
+
|
96
|
+
def quoted_time(value) # :nodoc:
|
97
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
98
|
+
quoted_date(value).sub(/\A\d{4}-\d{2}-\d{2} /, "")
|
99
|
+
end
|
100
|
+
|
101
|
+
def quote value, column = nil
|
102
|
+
case value
|
103
|
+
when Arel::Nodes::SqlLiteral
|
104
|
+
value
|
105
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
106
|
+
"'#{quote_string(value.to_s)}'"
|
107
|
+
when true
|
108
|
+
quoted_true
|
109
|
+
when false
|
110
|
+
quoted_false
|
111
|
+
when nil
|
112
|
+
'NULL'
|
113
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
114
|
+
when BigDecimal
|
115
|
+
value.to_s('F')
|
116
|
+
when Numeric, ActiveSupport::Duration
|
117
|
+
value.to_s
|
118
|
+
when Date, Time
|
119
|
+
"'#{quoted_date(value)}'"
|
120
|
+
when Class
|
121
|
+
"'#{value}'"
|
122
|
+
else
|
123
|
+
raise TypeError, "can't quote #{value.class.name}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
52
128
|
# Math Functions
|
53
129
|
def visit_ArelExtensions_Nodes_Ceil o, collector
|
54
130
|
collector << 'CEILING('
|
@@ -487,6 +563,11 @@ module ArelExtensions
|
|
487
563
|
collector
|
488
564
|
end
|
489
565
|
|
566
|
+
def visit_Arel_Nodes_RollUp(o, collector)
|
567
|
+
collector << "ROLLUP"
|
568
|
+
grouping_array_or_grouping_element o, collector
|
569
|
+
end
|
570
|
+
|
490
571
|
# TODO;
|
491
572
|
def visit_ArelExtensions_Nodes_GroupConcat o, collector
|
492
573
|
collector << '(STRING_AGG('
|
@@ -647,6 +728,18 @@ module ArelExtensions
|
|
647
728
|
collector << ')'
|
648
729
|
collector
|
649
730
|
end
|
731
|
+
|
732
|
+
# Utilized by GroupingSet, Cube & RollUp visitors to
|
733
|
+
# handle grouping aggregation semantics
|
734
|
+
def grouping_array_or_grouping_element(o, collector)
|
735
|
+
if o.expr.is_a? Array
|
736
|
+
collector << "( "
|
737
|
+
visit o.expr, collector
|
738
|
+
collector << " )"
|
739
|
+
else
|
740
|
+
visit o.expr, collector
|
741
|
+
end
|
742
|
+
end
|
650
743
|
end
|
651
744
|
end
|
652
745
|
end
|