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.
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
 
@@ -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
- t is an Arel::Table for table my_table
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 : ABS, RAND, ROUND, FLOOR, CEIL, FORMAT
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 '\^[a-d_]+'
98
+ # => my_table.name REGEXP '^[a-d_]+'
99
99
  ```
100
100
 
101
- Other functions : SOUNDEX, LENGTH, REPLACE, LOCATE, SUBSTRING, TRIM
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
- ```t[:list]``` is a classical varchar containing a comma separated list ("1,2,3,4")
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
- <td class="tg-yw4l">POSIX FORMATTING<br>column.format_number("$ %7.2f","en_US")</td>
325
- <td class="ok">✔</td>
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
- <th class="tg-ffjm" rowspan="17"><div>String functions</div></th>
334
- <td class="tg-yw4l">CONCAT<br>column + "string"</td>
358
+ <td class="tg-yw4l">FIND_IN_SET<br>column &amp; ("l")</td>
335
359
  <td class="ok">✔</td>
336
360
  <td class="ok">✔</td>
337
- <td class="tg-j6lv"> ||</td>
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">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>
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">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>
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">SOUNDEX<br>column.soundex</td>
430
+ <td class="tg-yw4l">NOT_REGEXP<br>column != "pattern"</td>
380
431
  <td class="ok">✔</td>
381
- <td class="tg-3oug">require fuzzystrmatch</td>
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">REGEXP<br>column =~ "pattern"<br></td>
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">NOT_REGEXP<br>column != "pattern"</td>
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">ILIKE (in Arel6)<br/>column.imatches('%pattern')</td>
416
- <td class="tg-j6lv">LOWER() LIKE LOWER()</td>
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="8"><div>Comparators functions</div></th>
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
@@ -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
@@ -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.2', platforms: [:mri]
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]
@@ -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.2', platforms: [:mri]
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]
@@ -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
@@ -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::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,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
@@ -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.7'.freeze
3
3
  end