arel_extensions 2.1.4 → 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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +162 -222
  3. data/.gitignore +7 -6
  4. data/.rubocop.yml +37 -0
  5. data/Gemfile +3 -3
  6. data/NEWS.md +15 -0
  7. data/README.md +119 -75
  8. data/appveyor.yml +82 -0
  9. data/arel_extensions.gemspec +0 -1
  10. data/gemfiles/rails3.gemfile +5 -5
  11. data/gemfiles/rails4_2.gemfile +38 -0
  12. data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +6 -6
  13. data/gemfiles/rails5_1_4.gemfile +6 -6
  14. data/gemfiles/rails5_2.gemfile +6 -5
  15. data/gemfiles/rails6.gemfile +5 -4
  16. data/gemfiles/rails6_1.gemfile +5 -4
  17. data/gemfiles/rails7.gemfile +5 -4
  18. data/gemspecs/arel_extensions-v1.gemspec +0 -1
  19. data/gemspecs/arel_extensions-v2.gemspec +0 -1
  20. data/lib/arel_extensions/common_sql_functions.rb +2 -2
  21. data/lib/arel_extensions/helpers.rb +12 -12
  22. data/lib/arel_extensions/math.rb +32 -17
  23. data/lib/arel_extensions/nodes/case.rb +4 -3
  24. data/lib/arel_extensions/nodes/cast.rb +2 -2
  25. data/lib/arel_extensions/nodes/coalesce.rb +1 -1
  26. data/lib/arel_extensions/nodes/collate.rb +1 -1
  27. data/lib/arel_extensions/nodes/date_diff.rb +6 -6
  28. data/lib/arel_extensions/nodes/locate.rb +1 -1
  29. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  30. data/lib/arel_extensions/nodes/rollup.rb +36 -0
  31. data/lib/arel_extensions/nodes/select.rb +10 -0
  32. data/lib/arel_extensions/nodes/substring.rb +1 -1
  33. data/lib/arel_extensions/nodes/then.rb +1 -1
  34. data/lib/arel_extensions/nodes/trim.rb +2 -2
  35. data/lib/arel_extensions/nodes/union.rb +3 -3
  36. data/lib/arel_extensions/nodes/union_all.rb +2 -2
  37. data/lib/arel_extensions/null_functions.rb +16 -0
  38. data/lib/arel_extensions/string_functions.rb +1 -0
  39. data/lib/arel_extensions/version.rb +1 -1
  40. data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
  41. data/lib/arel_extensions/visitors/mssql.rb +123 -17
  42. data/lib/arel_extensions/visitors/mysql.rb +78 -11
  43. data/lib/arel_extensions/visitors/oracle.rb +39 -17
  44. data/lib/arel_extensions/visitors/postgresql.rb +17 -12
  45. data/lib/arel_extensions/visitors/sqlite.rb +4 -4
  46. data/lib/arel_extensions/visitors/to_sql.rb +4 -1
  47. data/lib/arel_extensions/visitors.rb +8 -0
  48. data/lib/arel_extensions.rb +26 -0
  49. data/test/arelx_test_helper.rb +1 -1
  50. data/test/real_db_test.rb +5 -5
  51. data/test/support/fake_record.rb +1 -1
  52. data/test/visitors/test_bulk_insert_oracle.rb +3 -3
  53. data/test/visitors/test_bulk_insert_sqlite.rb +1 -1
  54. data/test/visitors/test_bulk_insert_to_sql.rb +1 -1
  55. data/test/visitors/test_to_sql.rb +6 -6
  56. data/test/with_ar/all_agnostic_test.rb +177 -70
  57. data/test/with_ar/insert_agnostic_test.rb +3 -3
  58. data/test/with_ar/test_bulk_sqlite.rb +1 -1
  59. data/version_v1.rb +1 -1
  60. data/version_v2.rb +1 -1
  61. metadata +8 -18
  62. data/gemfiles/rails4.gemfile +0 -29
@@ -73,6 +73,8 @@ module ArelExtensions
73
73
  @neg = User.where(id: u.id)
74
74
  u = User.create age: 15, name: 'Justin', created_at: d, score: 11.0
75
75
  @justin = User.where(id: u.id)
76
+ u = User.create age: nil, name: 'nilly', created_at: nil, score: nil
77
+ @nilly = User.where(id: u.id)
76
78
 
77
79
  @age = User.arel_table[:age]
78
80
  @name = User.arel_table[:name]
@@ -149,7 +151,7 @@ module ArelExtensions
149
151
  def test_rand
150
152
  assert 42 != User.select(Arel.rand.as('res')).first.res
151
153
  assert 0 <= User.select(Arel.rand.abs.as('res')).first.res
152
- assert_equal 9, User.order(Arel.rand).limit(50).count
154
+ assert_equal 10, User.order(Arel.rand).limit(50).count
153
155
  end
154
156
 
155
157
  def test_round
@@ -186,6 +188,49 @@ module ArelExtensions
186
188
  assert User.group(:score).count(:id).values.all?{|e| !e.nil?}
187
189
  end
188
190
 
191
+ def test_rollup
192
+ skip "sqlite not supported" if $sqlite
193
+ at = User.arel_table
194
+ # single
195
+ q = User.select(at[:name], at[:age].sum).group(Arel::Nodes::RollUp.new([at[:name]]))
196
+ assert q.to_a.length > 0
197
+
198
+ # multi
199
+ q = User.select(at[:name], at[:score], at[:age].sum).group(Arel::Nodes::RollUp.new([at[:score], at[:name]]))
200
+ assert q.to_a.length > 0
201
+
202
+ # hybrid
203
+ q = User.select(at[:name], at[:score], at[:age].sum).group(at[:score], Arel::Nodes::RollUp.new([at[:name]]))
204
+ assert q.to_a.length > 0
205
+
206
+ ## Using Arel.rollup which is less verbose than the original way
207
+
208
+ # simple
209
+ q = User.select(at[:name], at[:age].sum).group(Arel.rollup(at[:name]))
210
+ assert q.to_a.length > 0
211
+
212
+ # multi
213
+ q = User.select(at[:name], at[:score], at[:age].sum).group(Arel.rollup([at[:score], at[:name]]))
214
+ assert q.to_a.length > 0
215
+
216
+ # hybrid
217
+ q = User.select(at[:name], at[:score], at[:age].sum).group(at[:score], Arel.rollup([at[:name]]))
218
+ assert q.to_a.length > 0
219
+
220
+ ## Using at[:col].rollup which is handy for single column rollups
221
+
222
+ # simple
223
+ q = User.select(at[:name], at[:age].sum).group(at[:name].rollup)
224
+ assert q.to_a.length > 0
225
+
226
+ q = User.select(at[:name], at[:score], at[:age].sum).group(at[:name].rollup, at[:score].rollup)
227
+ assert q.to_a.length > 0
228
+
229
+ # hybrid
230
+ q = User.select(at[:name], at[:score], at[:age].sum).group(at[:name], at[:score].rollup)
231
+ assert q.to_a.length > 0
232
+ end
233
+
189
234
  # String Functions
190
235
  def test_concat
191
236
  assert_equal 'Camille Camille', t(@camille, @name + ' ' + @name)
@@ -193,16 +238,16 @@ module ArelExtensions
193
238
  assert_equal 'Test Laure', t(@laure, Arel.quoted('Test ') + @name)
194
239
 
195
240
  skip 'No group_concat in SqlServer before 2017' if @env_db == 'mssql'
196
- assert_equal 'Lucas Sophie', t(User.where(name: ['Lucas', 'Sophie']), @name.group_concat(' '))
197
- assert_equal 'Lucas,Sophie', t(User.where(name: ['Lucas', 'Sophie']), @name.group_concat(','))
198
- assert_equal 'Lucas,Sophie', t(User.where(name: ['Lucas', 'Sophie']), @name.group_concat)
241
+ assert_equal 'Lucas Sophie', t(User.where(name: %w[Lucas Sophie]), @name.group_concat(' '))
242
+ assert_equal 'Lucas,Sophie', t(User.where(name: %w[Lucas Sophie]), @name.group_concat(','))
243
+ assert_equal 'Lucas,Sophie', t(User.where(name: %w[Lucas Sophie]), @name.group_concat)
199
244
 
200
245
  skip 'No order in group_concat in SqlLite' if $sqlite
201
- assert_equal 'Arthur,Lucas,Sophie', t(User.where(name: ['Lucas', 'Sophie', 'Arthur']), @name.group_concat(',', @name.asc))
202
- assert_equal 'Sophie,Lucas,Arthur', t(User.where(name: ['Lucas', 'Sophie', 'Arthur']), @name.group_concat(',', @name.desc))
203
- assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: ['Lucas', 'Sophie', 'Arthur']), @name.group_concat(',', [@score.asc, @name.asc]))
204
- assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: ['Lucas', 'Sophie', 'Arthur']), @name.group_concat(',', @score.asc, @name.asc))
205
- assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: ['Lucas', 'Sophie', 'Arthur']), @name.group_concat(',', order: [@score.asc, @name.asc]))
246
+ assert_equal 'Arthur,Lucas,Sophie', t(User.where(name: %w[Lucas Sophie Arthur]), @name.group_concat(',', @name.asc))
247
+ assert_equal 'Sophie,Lucas,Arthur', t(User.where(name: %w[Lucas Sophie Arthur]), @name.group_concat(',', @name.desc))
248
+ assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: %w[Lucas Sophie Arthur]), @name.group_concat(',', [@score.asc, @name.asc]))
249
+ assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: %w[Lucas Sophie Arthur]), @name.group_concat(',', @score.asc, @name.asc))
250
+ assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: %w[Lucas Sophie Arthur]), @name.group_concat(',', order: [@score.asc, @name.asc]))
206
251
  end
207
252
 
208
253
  def test_length
@@ -294,16 +339,16 @@ module ArelExtensions
294
339
  skip "Sqlite version can't load extension for regexp" if $sqlite && $load_extension_disabled
295
340
  skip 'SQL Server does not know about REGEXP without extensions' if @env_db == 'mssql'
296
341
  assert_equal 1, User.where(@name =~ '^M').count
297
- assert_equal 7, User.where(@name !~ '^L').count
342
+ assert_equal 8, User.where(@name !~ '^L').count
298
343
  assert_equal 1, User.where(@name =~ /^M/).count
299
- assert_equal 7, User.where(@name !~ /^L/).count
344
+ assert_equal 8, User.where(@name !~ /^L/).count
300
345
  end
301
346
 
302
347
  def test_imatches
303
348
  # puts User.where(@name.imatches('m%')).to_sql
304
349
  assert_equal 1, User.where(@name.imatches('m%')).count
305
350
  assert_equal 4, User.where(@name.imatches_any(['L%', '%e'])).count
306
- assert_equal 7, User.where(@name.idoes_not_match('L%')).count
351
+ assert_equal 8, User.where(@name.idoes_not_match('L%')).count
307
352
  end
308
353
 
309
354
  def test_replace
@@ -328,8 +373,8 @@ module ArelExtensions
328
373
  skip "Sqlite version can't load extension for soundex" if $sqlite && $load_extension_disabled
329
374
  skip "PostgreSql version can't load extension for soundex" if @env_db == 'postgresql'
330
375
  assert_equal 'C540', t(@camille, @name.soundex)
331
- assert_equal 9, User.where(@name.soundex.eq(@name.soundex)).count
332
- assert_equal 9, User.where(@name.soundex == @name.soundex).count
376
+ assert_equal 10, User.where(@name.soundex.eq(@name.soundex)).count
377
+ assert_equal 10, User.where(@name.soundex == @name.soundex).count
333
378
  end
334
379
 
335
380
  def test_change_case
@@ -374,6 +419,23 @@ module ArelExtensions
374
419
  assert_equal 'true', t(@neg, @comments.not_blank.then('true', 'false'))
375
420
  end
376
421
 
422
+ # This test repeats a lot of `test_blank` cases.
423
+ def test_present
424
+ if @env_db == 'postgresql'
425
+ assert_includes [true, 't'], t(@myung, @name.present) # depends of adapter
426
+ assert_includes [false, 'f'], t(@myung, @comments.present)
427
+ end
428
+ assert_equal 1, @myung.where(@name.present).count
429
+ assert_equal 0, @myung.where(@comments.present).count
430
+ assert_equal 0, @sophie.where(@comments.present).count
431
+ assert_equal 0, @camille.where(@comments.present).count
432
+
433
+ assert_equal 1, @neg.where(@comments.present).count
434
+ assert_equal 'true', t(@myung, @name.present.then('true', 'false'))
435
+ assert_equal 'false', t(@myung, @comments.present.then('true', 'false'))
436
+ assert_equal 'true', t(@neg, @comments.present.then('true', 'false'))
437
+ end
438
+
377
439
  def test_format
378
440
  assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
379
441
  assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
@@ -419,27 +481,32 @@ module ArelExtensions
419
481
  }
420
482
  }
421
483
 
422
- skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !['mssql', 'mysql', 'oracle', 'postgresql'].include?(ENV['DB'])
484
+ skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !%w[mssql mysql oracle postgresql].include?(ENV['DB'])
485
+ # TODO: Standarize timezone conversion across all databases.
486
+ # This test case will be refactored and should work the same across all vendors.
487
+ if ENV['DB'] == 'mssql' && /Microsoft SQL Server (\d+)/.match(ActiveRecord::Base.connection.select_value('SELECT @@version'))[1].to_i < 2016
488
+ skip "SQL Server < 2016 is not currently supported"
489
+ end
423
490
 
424
491
  tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
425
492
 
426
493
  assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['utc']))
427
- assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['sao_paulo'] }))
428
- assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['tahiti'] }))
494
+ assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['sao_paulo']}))
495
+ assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['tahiti']}))
429
496
 
430
497
  # Skipping conversion from UTC to the desired timezones fails in SQL
431
498
  # Server and Postgres. This is mainly due to the fact that timezone
432
499
  # information is not preserved in the column itself.
433
500
  #
434
501
  # MySQL is happy to consider that times by default are in UTC.
435
- assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
502
+ assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
436
503
  refute_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['paris'])) if !['mysql'].include?(ENV['DB'])
437
504
 
438
505
  # Winter/Summer time
439
- assert_equal '2014/08/03 14:42:00', t(@lucas, (@updated_at + 5.months).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
506
+ assert_equal '2014/08/03 14:42:00', t(@lucas, (@updated_at + 5.months).format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
440
507
  if ENV['DB'] == 'mssql'
441
- assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
442
- assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
508
+ assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
509
+ assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
443
510
  else
444
511
  assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
445
512
  assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
@@ -463,7 +530,7 @@ module ArelExtensions
463
530
  end
464
531
 
465
532
  def test_format_iso_year_of_week
466
- skip "Unsupported ISO year of week for DB=#{ENV['DB']}" if ['mssql', 'sqlite'].include?(ENV['DB'])
533
+ skip "Unsupported ISO year of week for DB=#{ENV['DB']}" if %w[mssql sqlite].include?(ENV['DB'])
467
534
  assert_equal '2014', t(@lucas, @updated_at.format('%G'))
468
535
 
469
536
  {
@@ -480,7 +547,7 @@ module ArelExtensions
480
547
  end
481
548
 
482
549
  def test_format_date_with_names
483
- skip "#{ENV['DB']} does not support a variety of word-based formatting for month and day names" if ['mssql'].include?(ENV['DB'])
550
+ skip "#{ENV['DB']} does not support a variety of word-based formatting for month and day names" if %w[mssql sqlite].include?(ENV['DB'])
484
551
  assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
485
552
  assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
486
553
 
@@ -491,9 +558,9 @@ module ArelExtensions
491
558
 
492
559
  def switch_to_lang(lang)
493
560
  languages = {
494
- 'mssql' => { :en => 'English', :fr => 'French' },
495
- 'mysql' => { :en => 'en_US', :fr => 'fr_FR' },
496
- 'postgresql' => { :en => 'en_US.utf8', :fr => 'fr_FR.utf8' }
561
+ 'mssql' => {en: 'English', fr: 'French'},
562
+ 'mysql' => {en: 'en_US', fr: 'fr_FR'},
563
+ 'postgresql' => {en: 'en_US.utf8', fr: 'fr_FR.utf8'}
497
564
  }
498
565
 
499
566
  sql = {
@@ -513,27 +580,29 @@ module ArelExtensions
513
580
  #
514
581
  # Tests should assert one single thing in principle, but until we
515
582
  # refactor this whole thing, we'll have to do tricks of this sort.
516
- switch_to_lang(:en)
517
- case ENV['DB']
518
- when 'mysql', 'postgresql'
519
- assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
520
- assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
521
- when 'mssql'
522
- assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
523
- end
524
- switch_to_lang(:fr)
525
- case ENV['DB']
526
- when 'mysql'
527
- assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
528
- assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
529
- when 'postgresql'
530
- assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
531
- assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
532
- when 'mssql'
533
- assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
583
+ begin
584
+ switch_to_lang(:en)
585
+ case ENV['DB']
586
+ when 'mysql', 'postgresql'
587
+ assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
588
+ assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
589
+ when 'mssql'
590
+ assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
591
+ end
592
+ switch_to_lang(:fr)
593
+ case ENV['DB']
594
+ when 'mysql'
595
+ assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
596
+ assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
597
+ when 'postgresql'
598
+ assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
599
+ assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
600
+ when 'mssql'
601
+ assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
602
+ end
603
+ ensure
604
+ switch_to_lang(:en)
534
605
  end
535
- ensure
536
- switch_to_lang(:en)
537
606
  end
538
607
 
539
608
  def test_coalesce
@@ -558,6 +627,24 @@ module ArelExtensions
558
627
  assert_equal 'Laure10', t(@laure, @comments.coalesce('Laure') + 10)
559
628
  end
560
629
 
630
+ def test_coalesce_blank
631
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('Myung').coalesce_blank('ignored'))
632
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ').coalesce_blank('Myung'))
633
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ', 'Myung'))
634
+ assert_equal '2016-05-23', t(@myung, @created_at.coalesce_blank(Date.new(2022, 1, 1)).format('%Y-%m-%d'))
635
+ assert_equal 'Laure', t(@laure, @comments.coalesce_blank('Laure'))
636
+ assert_equal 100, t(@test, @age.coalesce_blank(100))
637
+ assert_equal 20, t(@test, @age.coalesce_blank(20))
638
+ assert_equal 20, t(@test, @age.coalesce_blank(10) + 10)
639
+ assert_equal 'Laure10', t(@laure, @comments.coalesce_blank('Laure') + 10)
640
+
641
+ skip 'mssql does not support null in case results' if @env_db == 'mssql'
642
+
643
+ assert_equal 'Camille concat', t(@camille, @name.coalesce_blank(Arel.null, 'default') + ' concat')
644
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank(Arel.null, 'Myung'))
645
+ assert_equal 'Camille', t(@camille, @name.coalesce_blank(Arel.null, 'default'))
646
+ end
647
+
561
648
  # Comparators
562
649
  def test_number_comparator
563
650
  assert_equal 2, User.where(@age < 6).count
@@ -570,7 +657,7 @@ module ArelExtensions
570
657
  def test_date_comparator
571
658
  d = Date.new(2016, 5, 23)
572
659
  assert_equal 0, User.where(@created_at < d).count
573
- assert_equal 9, User.where(@created_at >= d).count
660
+ assert_equal 10, User.where(@created_at >= d).count
574
661
  end
575
662
 
576
663
  def test_date_duration
@@ -602,8 +689,8 @@ module ArelExtensions
602
689
  def test_datetime_diff
603
690
  assert_equal 0, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 42)).to_i
604
691
  if @env_db == 'oracle' && Arel::VERSION.to_i > 6 # in rails 5, result is multiplied by 24*60*60 = 86400...
605
- assert_equal 42 * 86400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
606
- assert_equal(-3600 * 86400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
692
+ assert_equal 42 * 86_400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
693
+ assert_equal(-3600 * 86_400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
607
694
  else
608
695
  assert_equal 42, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
609
696
  assert_equal(-3600, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
@@ -658,12 +745,12 @@ module ArelExtensions
658
745
  # TODO; cast types
659
746
  def test_cast_types
660
747
  assert_equal '5', t(@lucas, @age.cast(:string))
661
- skip 'jdbc adapters does not work properly here (v52 works fine)' if RUBY_PLATFORM =~ /java/i
748
+ skip 'jdbc adapters does not work properly here (v52 works fine)' if RUBY_PLATFORM.match?(/java/i)
662
749
  if @env_db == 'mysql' || @env_db == 'postgresql' || @env_db == 'oracle' || @env_db == 'mssql'
663
750
  assert_equal 1, t(@laure, Arel.when(@duration.cast(:time).cast(:string).eq('12:42:21')).then(1).else(0)) unless @env_db == 'oracle' || @env_db == 'mssql'
664
751
  assert_equal 1, t(@laure, Arel.when(@duration.cast(:time).eq('12:42:21')).then(1).else(0)) unless @env_db == 'oracle'
665
- assert_equal '20.16', t(@laure, @score.cast(:string)).gsub(/[0]*\z/, '')
666
- assert_equal '20.161', t(@laure, @score.cast(:string) + 1).gsub(/[0]*1\z/, '1')
752
+ assert_equal '20.16', t(@laure, @score.cast(:string)).gsub(/0*\z/, '')
753
+ assert_equal '20.161', t(@laure, @score.cast(:string) + 1).gsub(/0*1\z/, '1')
667
754
  assert_equal 21.16, t(@laure, @score.cast(:string).cast(:decimal) + 1)
668
755
  assert_equal 21, t(@laure, @score.cast(:string).cast(:int) + 1)
669
756
 
@@ -683,6 +770,26 @@ module ArelExtensions
683
770
  end
684
771
  end
685
772
 
773
+ def test_if_present
774
+ assert_nil t(@myung, @comments.if_present)
775
+ assert_equal 0, t(@myung, @comments.if_present.count)
776
+ assert_equal 20.16, t(@myung, @score.if_present)
777
+ assert_equal '2016-05-23', t(@myung, @created_at.if_present.format('%Y-%m-%d'))
778
+ assert_nil t(@laure, @comments.if_present)
779
+
780
+ assert_nil t(@nilly, @duration.if_present.format('%Y-%m-%d'))
781
+
782
+ # NOTE: here we're testing the capacity to format a nil value,
783
+ # however, @comments is a text field, and not a date/datetime field,
784
+ # so Postgres will rightfully complain when we format the text:
785
+ # we need to cast it first.
786
+ if @env_db == 'postgresql'
787
+ assert_nil t(@laure, @comments.cast(:date).if_present.format('%Y-%m-%d'))
788
+ else
789
+ assert_nil t(@laure, @comments.if_present.format('%Y-%m-%d'))
790
+ end
791
+ end
792
+
686
793
  def test_is_null
687
794
  # puts User.where(@age.is_null).select(@name).to_sql
688
795
  # puts @age.is_null
@@ -718,7 +825,7 @@ module ArelExtensions
718
825
  def test_math_minus
719
826
  d = Date.new(2016, 5, 20)
720
827
  # Datediff
721
- assert_equal 9, User.where((@created_at - @created_at).eq(0)).count
828
+ assert_equal 10, User.where((@created_at - @created_at).eq(0)).count
722
829
  assert_equal 3, @laure.select((@created_at - d).as('res')).first.res.abs.to_i
723
830
  # Substraction
724
831
  assert_equal 0, User.where((@age - 10).eq(50)).count
@@ -747,8 +854,8 @@ module ArelExtensions
747
854
  assert_equal 3, User.select('*').from((@ut.project(@age).where(@age.eq(20)) + @ut.project(@age).where(@age.eq(23)) + @ut.project(@age).where(@age.eq(21))).as('my_union')).length
748
855
  assert_equal 2, User.select('*').from((@ut.project(@age).where(@age.eq(20)) + @ut.project(@age).where(@age.eq(20)) + @ut.project(@age).where(@age.eq(21))).as('my_union')).length
749
856
 
750
- assert_equal 3, User.find_by_sql((@ut.project(@age).where(@age.gt(22)).union_all(@ut.project(@age).where(@age.lt(0)))).to_sql).length
751
- assert_equal 3, User.find_by_sql((@ut.project(@age).where(@age.eq(20)).union_all(@ut.project(@age).where(@age.eq(20))).union_all(@ut.project(@age).where(@age.eq(21)))).to_sql).length
857
+ assert_equal 3, User.find_by_sql(@ut.project(@age).where(@age.gt(22)).union_all(@ut.project(@age).where(@age.lt(0))).to_sql).length
858
+ assert_equal 3, User.find_by_sql(@ut.project(@age).where(@age.eq(20)).union_all(@ut.project(@age).where(@age.eq(20))).union_all(@ut.project(@age).where(@age.eq(21))).to_sql).length
752
859
  assert_equal 3, User.select('*').from((@ut.project(@age).where(@age.gt(22)).union_all(@ut.project(@age).where(@age.lt(0)))).as('my_union')).length
753
860
  assert_equal 3, User.select('*').from((@ut.project(@age).where(@age.eq(20)).union_all(@ut.project(@age).where(@age.eq(23))).union_all(@ut.project(@age).where(@age.eq(21)))).as('my_union')).length
754
861
  assert_equal 3, User.select('*').from((@ut.project(@age).where(@age.eq(20)).union_all(@ut.project(@age).where(@age.eq(20))).union_all(@ut.project(@age).where(@age.eq(21)))).as('my_union')).length
@@ -786,10 +893,10 @@ module ArelExtensions
786
893
  assert_includes ['$ 6,56e1 €', '$ 6,56e+01 €'], t(@arthur, @score.format_number('$ %.2e €', 'fr_FR'))
787
894
  assert_includes ['$ 6,56E1 €', '$ 6,56E+01 €'], t(@arthur, @score.format_number('$ %.2E €', 'fr_FR'))
788
895
  assert_includes ['$ 6,562E1 €', '$ 6,562E+01 €'], t(@arthur, @score.format_number('$ %.3E €', 'fr_FR'))
789
- assert_equal '123 456 765,6', t(@arthur, (@score + 123456700).format_number('%.1f', 'sv_SE')).gsub("\u00A0", ' ') # some DBMS put no-break space here (it makes sense thus)
790
- assert_equal '123456765,6', t(@arthur, (@score + 123456700).format_number('%.1f', 'fr_FR')).gsub("\u00A0", '') # because SqlServer does it like no one else
791
- assert_equal '123,456,765.6', t(@arthur, (@score + 123456700).format_number('%.1f', 'en_US'))
792
- assert_equal ' 123,456,765.6', t(@arthur, (@score + 123456700).format_number('%16.1f', 'en_US'))
896
+ assert_equal '123 456 765,6', t(@arthur, (@score + 123_456_700).format_number('%.1f', 'sv_SE')).tr("\u00A0", ' ') # some DBMS put no-break space here (it makes sense thus)
897
+ assert_equal '123456765,6', t(@arthur, (@score + 123_456_700).format_number('%.1f', 'fr_FR')).delete("\u00A0") # because SqlServer does it like no one else
898
+ assert_equal '123,456,765.6', t(@arthur, (@score + 123_456_700).format_number('%.1f', 'en_US'))
899
+ assert_equal ' 123,456,765.6', t(@arthur, (@score + 123_456_700).format_number('%16.1f', 'en_US'))
793
900
  assert_equal '$ 0,00 €', t(@arthur, @score.when(65.62).then(Arel.sql('null')).else(1).format_number('$ %.2f €', 'fr_FR'))
794
901
  assert_equal '$ 0,00 €', t(@arthur, (@score - 65.62).format_number('$ %.2f €', 'fr_FR'))
795
902
  end
@@ -811,7 +918,7 @@ module ArelExtensions
811
918
  assert_equal '1', t(@arthur, Arel.when(@comments.ai_matches('arrete')).then('1').else('0'))
812
919
  assert_equal '1', t(@arthur, Arel.when(@comments.ai_matches('àrrétè')).then('1').else('0'))
813
920
  assert_equal '0', t(@arthur, Arel.when(@comments.ai_matches('arretez')).then('1').else('0'))
814
- if !['oracle', 'postgresql', 'mysql'].include?(@env_db) # AI => CI
921
+ if !%w[oracle postgresql mysql].include?(@env_db) # AI => CI
815
922
  assert_equal '0', t(@arthur, Arel.when(@comments.ai_matches('Arrete')).then('1').else('0'))
816
923
  assert_equal '0', t(@arthur, Arel.when(@comments.ai_matches('Arrêté')).then('1').else('0'))
817
924
  end
@@ -838,8 +945,8 @@ module ArelExtensions
838
945
 
839
946
  def test_subquery_with_order
840
947
  skip if ['mssql'].include?(@env_db) && Arel::VERSION.to_i < 10
841
- assert_equal 9, User.where(name: User.select(:name).order(:name)).count
842
- assert_equal 9, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
948
+ assert_equal 10, User.where(name: User.select(:name).order(:name)).count
949
+ assert_equal 10, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
843
950
  if !['mysql'].include?(@env_db) # MySql can't have limit in IN subquery
844
951
  assert_equal 2, User.where(name: User.select(:name).order(:name).limit(2)).count
845
952
  # assert_equal 6, User.where(name: User.select(:name).order(:name).offset(2)).count
@@ -915,7 +1022,7 @@ module ArelExtensions
915
1022
  end
916
1023
 
917
1024
  def test_alias_shortened
918
- if ['postgresql', 'oracle'].include?(@env_db)
1025
+ if %w[postgresql oracle].include?(@env_db)
919
1026
  new_alias = Arel.shorten('azerty' * 15)
920
1027
  at = User.arel_table.alias('azerty' * 15)
921
1028
  assert_equal "\"user_tests\" \"#{new_alias}\"".downcase, User.arel_table.alias('azerty' * 15).to_sql.downcase
@@ -956,23 +1063,23 @@ module ArelExtensions
956
1063
  skip "Can't be tested on travis"
957
1064
  # creation
958
1065
  assert_equal 'Arthur', t(@arthur, Arel.json(@name))
959
- assert_equal ['Arthur', 'Arthur'], parse_json(t(@arthur, Arel.json(@name, @name)))
1066
+ assert_equal %w[Arthur Arthur], parse_json(t(@arthur, Arel.json(@name, @name)))
960
1067
  assert_equal ({'Arthur' => 'Arthur', 'Arthur2' => 'ArthurArthur'}), parse_json(t(@arthur, Arel.json({@name => @name, @name + '2' => @name + @name})))
961
1068
  assert_equal ({'Arthur' => 'Arthur', 'Arthur2' => 1}), parse_json(t(@arthur, Arel.json({@name => @name, @name + '2' => 1})))
962
- assert_equal ([{'age' => 21}, {'name' => 'Arthur', 'score' => 65.62}]), parse_json(t(@arthur, Arel.json([{age: @age}, {name: @name, score: @score}])))
1069
+ assert_equal [{'age' => 21}, {'name' => 'Arthur', 'score' => 65.62}], parse_json(t(@arthur, Arel.json([{age: @age}, {name: @name, score: @score}])))
963
1070
 
964
1071
  # aggregate
965
1072
  assert_equal ({'5' => 'Lucas', '15' => 'Sophie', '23' => 'Myung', '25' => 'Laure'}),
966
1073
  parse_json(t(User.group(:score).where(@age.is_not_null).where(@score == 20.16), Arel.json({@age => @name}).group(false)))
967
1074
  assert_equal ({'5' => 'Lucas', '15' => 'Sophie', '23' => 'Myung', '25' => 'Laure', 'Laure' => 25, 'Lucas' => 5, 'Myung' => 23, 'Sophie' => 15}),
968
1075
  parse_json(t(User.group(:score).where(@age.is_not_null).where(@score == 20.16), Arel.json({@age => @name, @name => @age}).group(false)))
969
- assert_equal ([{'5' => 'Lucas'}, { '15' => 'Sophie'}, { '23' => 'Myung'}, { '25' => 'Laure'}]),
1076
+ assert_equal [{'5' => 'Lucas'}, {'15' => 'Sophie'}, {'23' => 'Myung'}, {'25' => 'Laure'}],
970
1077
  parse_json(t(User.group(:score).where(@age.is_not_null).where(@score == 20.16).select(@score), Arel.json({@age => @name}).group(true, [@age])))
971
1078
 
972
1079
  # puts User.group(:score).where(@age.is_not_null).where(@score == 20.16).select(@score, Arel.json({@age => @name}).group(true,[@age])).to_sql
973
1080
  # puts User.group(:score).where(@age.is_not_null).where(@score == 20.16).select(@score, Arel.json({@age => @name}).group(true,[@age])).to_a
974
1081
 
975
- skip 'Not Yet Implemented' if $sqlite || ['oracle', 'mssql'].include?(@env_db)
1082
+ skip 'Not Yet Implemented' if $sqlite || %w[oracle mssql].include?(@env_db)
976
1083
  # get
977
1084
  h1 = Arel.json({@name => @name + @name, @name + '2' => 1})
978
1085
  assert_equal 'ArthurArthur', parse_json(t(@arthur, h1.get(@name)))
@@ -981,13 +1088,13 @@ module ArelExtensions
981
1088
  assert_equal 21, parse_json(t(@arthur, h2.get(0).get('age')))
982
1089
  assert_nil t(@arthur, h2.get('age'))
983
1090
  # set
984
- assert_equal ({'Arthur' => ['toto', 'tata'], 'Arthur2' => 1}), parse_json(t(@arthur, h1.set(@name, ['toto', 'tata'])))
1091
+ assert_equal ({'Arthur' => %w[toto tata], 'Arthur2' => 1}), parse_json(t(@arthur, h1.set(@name, %w[toto tata])))
985
1092
  assert_equal ({'Arthur' => 'ArthurArthur', 'Arthur2' => 1, 'Arthur3' => 2}), parse_json(t(@arthur, h1.set(@name + '3', 2)))
986
1093
  assert_equal ({'Arthur' => 'ArthurArthur', 'Arthur2' => 1, 'Arthur3' => nil}), parse_json(t(@arthur, h1.set(@name + '3', nil)))
987
1094
  assert_equal ({'Arthur' => 'ArthurArthur', 'Arthur2' => 1, 'Arthur3' => {'a' => 2}}), parse_json(t(@arthur, h1.set(@name + '3', {a: 2})))
988
1095
  # merge
989
- assert_equal ({'Arthur' => ['toto', 'tata'], 'Arthur2' => 1, 'Arthur3' => 2}), parse_json(t(@arthur, h1.merge({@name => ['toto', 'tata']}, {@name + '3' => 2})))
990
- assert_equal ({'Arthur' => ['toto', 'tata'], 'Arthur2' => 1, 'Arthur3' => 2}), parse_json(t(@arthur, h1.merge({@name => ['toto', 'tata'], @name + '3' => 2})))
1096
+ assert_equal ({'Arthur' => %w[toto tata], 'Arthur2' => 1, 'Arthur3' => 2}), parse_json(t(@arthur, h1.merge({@name => %w[toto tata]}, {@name + '3' => 2})))
1097
+ assert_equal ({'Arthur' => %w[toto tata], 'Arthur2' => 1, 'Arthur3' => 2}), parse_json(t(@arthur, h1.merge({@name => %w[toto tata], @name + '3' => 2})))
991
1098
  assert_equal ({'Arthur' => 'ArthurArthur', 'Arthur2' => 1}), parse_json(t(@arthur, h1.merge({})))
992
1099
  end
993
1100
 
@@ -58,15 +58,15 @@ END;])
58
58
  connect_db
59
59
  setup_db
60
60
  @table = Arel::Table.new(:user_tests)
61
- @cols = ['id', 'name', 'comments', 'created_at']
61
+ @cols = %w[id name comments created_at]
62
62
  @data = [
63
63
  [23, 'nom1', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.', '2016-01-01'],
64
64
  [25, 'nom2', 'sdfdsfdsfsdf', '2016-01-02']
65
65
  ]
66
- @cols2 = ['name', 'comments', 'created_at']
66
+ @cols2 = %w[name comments created_at]
67
67
  @data2 = [
68
68
  ['nom3', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.', '2016-01-01'],
69
- ['nom4', 'sdfdsfdsfsdf', '2016-01-04']
69
+ %w[nom4 sdfdsfdsfsdf 2016-01-04]
70
70
  ]
71
71
  end
72
72
 
@@ -27,7 +27,7 @@ module ArelExtensions
27
27
  t.column :price, :decimal
28
28
  end
29
29
  @table = Arel::Table.new(:users)
30
- @cols = ['id', 'name', 'comments', 'created_at']
30
+ @cols = %w[id name comments created_at]
31
31
  @data = [
32
32
  [23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01'],
33
33
  [25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
data/version_v1.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '1.3.4'.freeze
2
+ VERSION = '1.3.6'.freeze
3
3
  end
data/version_v2.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '2.1.4'.freeze
2
+ VERSION = '2.1.6'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arel_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.4
4
+ version: 2.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yann Azoury
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-03-24 00:00:00.000000000 Z
13
+ date: 2022-11-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -40,20 +40,6 @@ dependencies:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '5.9'
43
- - !ruby/object:Gem::Dependency
44
- name: rdoc
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 6.3.1
50
- type: :development
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: 6.3.1
57
43
  - !ruby/object:Gem::Dependency
58
44
  name: rake
59
45
  requirement: !ruby/object:Gem::Requirement
@@ -86,15 +72,17 @@ files:
86
72
  - ".rubocop.yml"
87
73
  - Gemfile
88
74
  - MIT-LICENSE.txt
75
+ - NEWS.md
89
76
  - README.md
90
77
  - Rakefile
91
78
  - SQL_Challenges.md
92
79
  - TODO
80
+ - appveyor.yml
93
81
  - arel_extensions.gemspec
94
82
  - functions.html
95
83
  - gemfiles/rails3.gemfile
96
- - gemfiles/rails4.gemfile
97
- - gemfiles/rails5_0.gemfile
84
+ - gemfiles/rails4_2.gemfile
85
+ - gemfiles/rails5.gemfile
98
86
  - gemfiles/rails5_1_4.gemfile
99
87
  - gemfiles/rails5_2.gemfile
100
88
  - gemfiles/rails6.gemfile
@@ -149,7 +137,9 @@ files:
149
137
  - lib/arel_extensions/nodes/rand.rb
150
138
  - lib/arel_extensions/nodes/repeat.rb
151
139
  - lib/arel_extensions/nodes/replace.rb
140
+ - lib/arel_extensions/nodes/rollup.rb
152
141
  - lib/arel_extensions/nodes/round.rb
142
+ - lib/arel_extensions/nodes/select.rb
153
143
  - lib/arel_extensions/nodes/soundex.rb
154
144
  - lib/arel_extensions/nodes/std.rb
155
145
  - lib/arel_extensions/nodes/substring.rb
@@ -1,29 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'arel', '~> 6.0'
4
-
5
- group :development, :test do
6
- gem 'activesupport', '~> 4.0'
7
- gem 'activemodel', '~> 4.0'
8
- gem 'activerecord', '~> 4.0'
9
-
10
- gem 'sqlite3', '<= 1.3.13', platforms: [:mri, :mswin, :mingw]
11
- gem 'mysql2', '0.4.10', platforms: [:mri, :mswin, :mingw]
12
- gem 'pg', '< 1.0.0', platforms: [:mri, :mingw]
13
-
14
- gem 'tiny_tds', platforms: [:mri, :mingw, :mswin] if RUBY_PLATFORM =~ /windows/
15
- gem 'activerecord-sqlserver-adapter', '~> 4.2.0', platforms: [:mri, :mingw, :mswin] if RUBY_PLATFORM =~ /windows/
16
-
17
- gem 'ruby-oci8', platforms: [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
18
- gem 'activerecord-oracle_enhanced-adapter', '~> 1.6.0' if ENV.has_key? 'ORACLE_HOME'
19
-
20
- # for JRuby
21
- gem 'activerecord-jdbc-adapter', '~> 1.3', platforms: :jruby
22
- gem 'jdbc-sqlite3', platforms: :jruby
23
- gem 'activerecord-jdbcsqlite3-adapter', platforms: :jruby
24
- gem 'activerecord-jdbcmysql-adapter', platforms: :jruby
25
- gem 'activerecord-jdbcpostgresql-adapter', platforms: :jruby
26
- gem 'activerecord-jdbcmssql-adapter', platforms: :jruby
27
- end
28
-
29
- gemspec path: '../'