arel_extensions 1.3.5 → 1.3.7

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
 
@@ -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('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
@@ -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 = '1.3.5'.freeze
2
+ VERSION = '1.3.7'.freeze
3
3
  end