arel_extensions 2.1.5 → 2.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,16 +1,15 @@
1
1
  # Arel Extensions
2
2
 
3
3
  ![GitHub workflow](https://github.com/Faveod/arel-extensions/actions/workflows/ruby.yml/badge.svg)
4
- [![AppVeyor Build Status](https://img.shields.io/appveyor/ci/yazfav/arel-extensions.svg?label=AppVeyor%20build)](https://ci.appveyor.com/project/yazfav/arel-extensions)
5
- [![Security](https://hakiri.io/github/Faveod/arel-extensions/master.svg)](https://hakiri.io/github/Faveod/arel-extensions/master)
4
+ [![AppVeyor Build Status](https://img.shields.io/appveyor/ci/jdelporte/arel-extensions.svg?label=AppVeyor%20build)](https://ci.appveyor.com/project/jdelporte/arel-extensions)
6
5
  ![](http://img.shields.io/badge/license-MIT-brightgreen.svg)
7
6
 
8
7
  Gem: [![Latest Release](https://img.shields.io/gem/v/arel_extensions.svg)](https://rubygems.org/gems/arel_extensions)
9
8
  [![Gem](https://ruby-gem-downloads-badge.herokuapp.com/arel_extensions?type=total)](https://rubygems.org/gems/arel_extensions)
10
9
  [![Gem](https://ruby-gem-downloads-badge.herokuapp.com/arel_extensions?label=downloads-current-version)](https://rubygems.org/gems/arel_extensions)
11
10
 
12
- Arel Extensions adds shortcuts, fixes and new ORM mappings (ruby to SQL) to Arel.
13
- It aims to ensure pure ruby syntax for the biggest number of usual cases.
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
- <td class="tg-yw4l">POSIX FORMATTING<br>column.format_number("$ %7.2f","en_US")</td>
325
- <td class="ok">✔</td>
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
- <th class="tg-ffjm" rowspan="17"><div>String functions</div></th>
334
- <td class="tg-yw4l">CONCAT<br>column + "string"</td>
342
+ <td class="tg-yw4l">FIND_IN_SET<br>column &amp; ("l")</td>
335
343
  <td class="ok">✔</td>
336
344
  <td class="ok">✔</td>
337
- <td class="tg-j6lv"> ||</td>
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">SUBSTRING<br/>column[1..2]<br/>column.substring(1)<br/>column.substring(1, 1)</td>
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">FIND_IN_SET<br>column &amp; ("l")</td>
371
- <td class="ok">✔</td>
372
- <td class="ok">✔</td>
373
- <td class="tg-orpl">Ruby function</td>
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">SOUNDEX<br>column.soundex</td>
414
+ <td class="tg-yw4l">NOT_REGEXP<br>column != "pattern"</td>
380
415
  <td class="ok">✔</td>
381
- <td class="tg-3oug">require fuzzystrmatch</td>
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">REGEXP<br>column =~ "pattern"<br></td>
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">ILIKE (in Arel6)<br/>column.imatches('%pattern')</td>
416
- <td class="tg-j6lv">LOWER() LIKE LOWER()</td>
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="8"><div>Comparators functions</div></th>
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
@@ -23,6 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency('activerecord', '>= 6.0')
24
24
 
25
25
  s.add_development_dependency('minitest', '~> 5.9')
26
- s.add_development_dependency('rdoc', '>= 6.3.1')
27
26
  s.add_development_dependency('rake', '~> 12.3.3')
28
27
  end
@@ -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] if RUBY_PLATFORM.match?(/windows/)
15
- gem 'activerecord-sqlserver-adapter', '~> 4.2.0', platforms: %i[mri mingw mswin] if RUBY_PLATFORM.match?(/windows/)
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
@@ -23,6 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency('arel', '>= 6.0')
24
24
 
25
25
  s.add_development_dependency('minitest', '~> 5.9')
26
- s.add_development_dependency('rdoc', '>= 6.3.1')
27
26
  s.add_development_dependency('rake', '~> 12.3.3')
28
27
  end
@@ -23,6 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency('activerecord', '>= 6.0')
24
24
 
25
25
  s.add_development_dependency('minitest', '~> 5.9')
26
- s.add_development_dependency('rdoc', '>= 6.3.1')
27
26
  s.add_development_dependency('rake', '~> 12.3.3')
28
27
  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::Predications
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
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ class SelectCore
4
+ # havings did not exist in rails < 5.2
5
+ if !method_defined?(:havings)
6
+ alias :havings :having
7
+ end
8
+ end
9
+ end
10
+ 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
@@ -184,6 +184,7 @@ module ArelExtensions
184
184
  def not_blank
185
185
  ArelExtensions::Nodes::NotBlank.new [self]
186
186
  end
187
+ alias present not_blank
187
188
 
188
189
  def repeat other = 1
189
190
  ArelExtensions::Nodes::Repeat.new [self, other]
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '2.1.5'.freeze
2
+ VERSION = '2.1.6'.freeze
3
3
  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