arel_extensions 2.1.5 → 2.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)
@@ -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,124 +419,152 @@ module ArelExtensions
374
419
  assert_equal 'true', t(@neg, @comments.not_blank.then('true', 'false'))
375
420
  end
376
421
 
377
- def test_format
378
- assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
379
- assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
380
- assert_equal '12:42%', t(@lucas, @updated_at.format('%R%%'))
381
-
382
- # The following tests will ensure proper conversion of timestamps to
383
- # requested timezones.
384
- #
385
- # The names of the timezones is highly dependant on the underlying
386
- # operating system, and this is why we need to handle each database
387
- # separately: the images we're using to test these databases are
388
- # different. So don't rely on the provided examples. Your setup is your
389
- # reference.
390
- #
391
- # One could always have portable code if s/he uses standard
392
- # abbreviations, like:
393
- #
394
- # 1. CET => Central European Time
395
- # 2. CEST => Central European Summer Time
396
- #
397
- # Which implies that the caller should handle daylight saving detection.
398
- # In fact, CET will handle daylight saving in MySQL but not Postgres.
399
- #
400
- # It looks like the posix convention is supported by mysql and
401
- # postgresql, e.g.:
402
- #
403
- # posix/Europe/Paris
404
- # posix/America/Nipigon
405
- #
406
- # so it looks like a more reliably portable way of specifying it.
407
- time_zones = {
408
- 'mssql' => {
409
- 'utc' => 'UTC',
410
- 'sao_paulo' => 'Argentina Standard Time',
411
- 'tahiti' => 'Hawaiian Standard Time',
412
- 'paris' => 'Central European Standard Time'
413
- },
414
- 'posix' => {
415
- 'utc' => 'UTC',
416
- 'sao_paulo' => 'America/Sao_Paulo',
417
- 'tahiti' => 'Pacific/Tahiti',
418
- 'paris' => 'Europe/Paris'
419
- }
420
- }
421
-
422
- skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !%w[mssql mysql oracle postgresql].include?(ENV['DB'])
423
- # TODO: Standarize timezone conversion across all databases.
424
- # This test case will be refactored and should work the same across all vendors.
425
- if ENV['DB'] == 'mssql' && /Microsoft SQL Server (\d+)/.match(ActiveRecord::Base.connection.select_value('SELECT @@version'))[1].to_i < 2016
426
- skip "SQL Server < 2016 is not currently supported"
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
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
428
432
 
429
- tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
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
430
438
 
431
- assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['utc']))
432
- assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['sao_paulo']}))
433
- assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['tahiti']}))
439
+ def test_format
440
+ %i[format format_date].each do |method|
441
+ assert_equal '2016-05-23', t(@lucas, @created_at.send(method, '%Y-%m-%d'))
442
+ assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S'))
443
+ assert_equal '12:42%', t(@lucas, @updated_at.send(method, '%R%%'))
444
+
445
+ # The following tests will ensure proper conversion of timestamps to
446
+ # requested timezones.
447
+ #
448
+ # The names of the timezones is highly dependant on the underlying
449
+ # operating system, and this is why we need to handle each database
450
+ # separately: the images we're using to test these databases are
451
+ # different. So don't rely on the provided examples. Your setup is your
452
+ # reference.
453
+ #
454
+ # One could always have portable code if s/he uses standard
455
+ # abbreviations, like:
456
+ #
457
+ # 1. CET => Central European Time
458
+ # 2. CEST => Central European Summer Time
459
+ #
460
+ # Which implies that the caller should handle daylight saving detection.
461
+ # In fact, CET will handle daylight saving in MySQL but not Postgres.
462
+ #
463
+ # It looks like the posix convention is supported by mysql and
464
+ # postgresql, e.g.:
465
+ #
466
+ # posix/Europe/Paris
467
+ # posix/America/Nipigon
468
+ #
469
+ # so it looks like a more reliably portable way of specifying it.
470
+ time_zones = {
471
+ 'mssql' => {
472
+ 'utc' => 'UTC',
473
+ 'sao_paulo' => 'Argentina Standard Time',
474
+ 'tahiti' => 'Hawaiian Standard Time',
475
+ 'paris' => 'Central European Standard Time'
476
+ },
477
+ 'posix' => {
478
+ 'utc' => 'UTC',
479
+ 'sao_paulo' => 'America/Sao_Paulo',
480
+ 'tahiti' => 'Pacific/Tahiti',
481
+ 'paris' => 'Europe/Paris'
482
+ }
483
+ }
484
+
485
+ skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !%w[mssql mysql oracle postgresql].include?(ENV['DB'])
486
+ # TODO: Standarize timezone conversion across all databases.
487
+ # This test case will be refactored and should work the same across all vendors.
488
+ if ENV['DB'] == 'mssql' && /Microsoft SQL Server (\d+)/.match(ActiveRecord::Base.connection.select_value('SELECT @@version'))[1].to_i < 2016
489
+ skip "SQL Server < 2016 is not currently supported"
490
+ end
434
491
 
435
- # Skipping conversion from UTC to the desired timezones fails in SQL
436
- # Server and Postgres. This is mainly due to the fact that timezone
437
- # information is not preserved in the column itself.
438
- #
439
- # MySQL is happy to consider that times by default are in UTC.
440
- assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
441
- 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'])
442
-
443
- # Winter/Summer time
444
- 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']}))
445
- if ENV['DB'] == 'mssql'
446
- 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']}))
447
- 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']}))
448
- else
449
- 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']))
450
- 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']))
492
+ tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
493
+
494
+ assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', tz['utc']))
495
+ assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['sao_paulo']}))
496
+ assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['tahiti']}))
497
+
498
+ # Skipping conversion from UTC to the desired timezones fails in SQL
499
+ # Server and Postgres. This is mainly due to the fact that timezone
500
+ # information is not preserved in the column itself.
501
+ #
502
+ # MySQL is happy to consider that times by default are in UTC.
503
+ assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
504
+ refute_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', tz['paris'])) if !['mysql'].include?(ENV['DB'])
505
+
506
+ # Winter/Summer time
507
+ assert_equal '2014/08/03 14:42:00', t(@lucas, (@updated_at + 5.months).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
508
+ if ENV['DB'] == 'mssql'
509
+ assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
510
+ assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
511
+ else
512
+ assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', tz['paris']))
513
+ assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', tz['paris']))
514
+ end
451
515
  end
452
516
  end
453
517
 
454
518
  def test_format_iso_week
455
- skip "Unsupported ISO week number for DB=#{ENV['DB']}" if ['sqlite'].include?(ENV['DB'])
456
- assert_equal '10', t(@lucas, @updated_at.format('%V'))
457
- {
458
- '2024-01-01 10:42:00' => '01', # Monday
459
- '2030-01-01 10:42:00' => '01', # Tuesday
460
- '2025-01-01 10:42:00' => '01', # Wednesday
461
- '2026-01-01 10:42:00' => '01', # Thursday
462
- '2027-01-01 10:42:00' => '53', # Friday
463
- '2028-01-01 10:42:00' => '52', # Saturday
464
- '2034-01-01 10:42:00' => '52', # Sunday
465
- }.each do |date, exp|
466
- assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).format('%V'))
519
+ %i[format format_date].each do |method|
520
+ skip "Unsupported ISO week number for DB=#{ENV['DB']}" if ['sqlite'].include?(ENV['DB'])
521
+ assert_equal '10', t(@lucas, @updated_at.send(method, '%V'))
522
+ {
523
+ '2024-01-01 10:42:00' => '01', # Monday
524
+ '2030-01-01 10:42:00' => '01', # Tuesday
525
+ '2025-01-01 10:42:00' => '01', # Wednesday
526
+ '2026-01-01 10:42:00' => '01', # Thursday
527
+ '2027-01-01 10:42:00' => '53', # Friday
528
+ '2028-01-01 10:42:00' => '52', # Saturday
529
+ '2034-01-01 10:42:00' => '52', # Sunday
530
+ }.each do |date, exp|
531
+ assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).send(method, '%V'))
532
+ end
467
533
  end
468
534
  end
469
535
 
470
536
  def test_format_iso_year_of_week
471
537
  skip "Unsupported ISO year of week for DB=#{ENV['DB']}" if %w[mssql sqlite].include?(ENV['DB'])
472
- assert_equal '2014', t(@lucas, @updated_at.format('%G'))
473
-
474
- {
475
- '2024-01-01 10:42:00' => '2024', # Monday
476
- '2030-01-01 10:42:00' => '2030', # Tuesday
477
- '2025-01-01 10:42:00' => '2025', # Wednesday
478
- '2026-01-01 10:42:00' => '2026', # Thursday
479
- '2027-01-01 10:42:00' => '2026', # Friday
480
- '2028-01-01 10:42:00' => '2027', # Saturday
481
- '2034-01-01 10:42:00' => '2033', # Sunday
482
- }.each do |date, exp|
483
- assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).format('%G'))
538
+ %i[format format_date].each do |method|
539
+ assert_equal '2014', t(@lucas, @updated_at.send(method, '%G'))
540
+
541
+ {
542
+ '2024-01-01 10:42:00' => '2024', # Monday
543
+ '2030-01-01 10:42:00' => '2030', # Tuesday
544
+ '2025-01-01 10:42:00' => '2025', # Wednesday
545
+ '2026-01-01 10:42:00' => '2026', # Thursday
546
+ '2027-01-01 10:42:00' => '2026', # Friday
547
+ '2028-01-01 10:42:00' => '2027', # Saturday
548
+ '2034-01-01 10:42:00' => '2033', # Sunday
549
+ }.each do |date, exp|
550
+ assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).send(method, '%G'))
551
+ end
484
552
  end
485
553
  end
486
554
 
487
555
  def test_format_date_with_names
488
556
  skip "#{ENV['DB']} does not support a variety of word-based formatting for month and day names" if %w[mssql sqlite].include?(ENV['DB'])
489
- assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
490
- assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
557
+ %i[format format_date].each do |method|
558
+ assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
559
+ assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
560
+ end
491
561
 
492
562
  skip "#{ENV['DB']} does not support ALLCAPS month and day names" if ['mysql'].include?(ENV['DB'])
493
- assert_equal 'Mon, 03 MAR 14', t(@lucas, @updated_at.format('%a, %d %^b %y'))
494
- assert_equal 'Monday, 03 MARCH 14', t(@lucas, @updated_at.format('%A, %d %^B %y'))
563
+ %i[format format_date].each do |method|
564
+
565
+ assert_equal 'Mon, 03 MAR 14', t(@lucas, @updated_at.send(method, '%a, %d %^b %y'))
566
+ assert_equal 'Monday, 03 MARCH 14', t(@lucas, @updated_at.send(method, '%A, %d %^B %y'))
567
+ end
495
568
  end
496
569
 
497
570
  def switch_to_lang(lang)
@@ -518,28 +591,30 @@ module ArelExtensions
518
591
  #
519
592
  # Tests should assert one single thing in principle, but until we
520
593
  # refactor this whole thing, we'll have to do tricks of this sort.
521
- begin
522
- switch_to_lang(:en)
523
- case ENV['DB']
524
- when 'mysql', 'postgresql'
525
- assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
526
- assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
527
- when 'mssql'
528
- assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
594
+ %i[format format_date].each do |method|
595
+ begin
596
+ switch_to_lang(:en)
597
+ case ENV['DB']
598
+ when 'mysql', 'postgresql'
599
+ assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
600
+ assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
601
+ when 'mssql'
602
+ assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
603
+ end
604
+ switch_to_lang(:fr)
605
+ case ENV['DB']
606
+ when 'mysql'
607
+ assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
608
+ assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
609
+ when 'postgresql'
610
+ assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
611
+ assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
612
+ when 'mssql'
613
+ assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
614
+ end
615
+ ensure
616
+ switch_to_lang(:en)
529
617
  end
530
- switch_to_lang(:fr)
531
- case ENV['DB']
532
- when 'mysql'
533
- assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
534
- assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
535
- when 'postgresql'
536
- assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
537
- assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
538
- when 'mssql'
539
- assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
540
- end
541
- ensure
542
- switch_to_lang(:en)
543
618
  end
544
619
  end
545
620
 
@@ -565,6 +640,25 @@ module ArelExtensions
565
640
  assert_equal 'Laure10', t(@laure, @comments.coalesce('Laure') + 10)
566
641
  end
567
642
 
643
+ def test_coalesce_blank
644
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('Myung').coalesce_blank('ignored'))
645
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ').coalesce_blank('Myung'))
646
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ', 'Myung'))
647
+ assert_equal '2016-05-23', t(@myung, @created_at.coalesce_blank(Date.new(2022, 1, 1)).format('%Y-%m-%d'))
648
+ assert_equal '2016-05-23', t(@myung, @created_at.coalesce_blank(Date.new(2022, 1, 1)).format_date('%Y-%m-%d'))
649
+ assert_equal 'Laure', t(@laure, @comments.coalesce_blank('Laure'))
650
+ assert_equal 100, t(@test, @age.coalesce_blank(100))
651
+ assert_equal 20, t(@test, @age.coalesce_blank(20))
652
+ assert_equal 20, t(@test, @age.coalesce_blank(10) + 10)
653
+ assert_equal 'Laure10', t(@laure, @comments.coalesce_blank('Laure') + 10)
654
+
655
+ skip 'mssql does not support null in case results' if @env_db == 'mssql'
656
+
657
+ assert_equal 'Camille concat', t(@camille, @name.coalesce_blank(Arel.null, 'default') + ' concat')
658
+ assert_equal 'Myung', t(@myung, @comments.coalesce_blank(Arel.null, 'Myung'))
659
+ assert_equal 'Camille', t(@camille, @name.coalesce_blank(Arel.null, 'default'))
660
+ end
661
+
568
662
  # Comparators
569
663
  def test_number_comparator
570
664
  assert_equal 2, User.where(@age < 6).count
@@ -577,7 +671,7 @@ module ArelExtensions
577
671
  def test_date_comparator
578
672
  d = Date.new(2016, 5, 23)
579
673
  assert_equal 0, User.where(@created_at < d).count
580
- assert_equal 9, User.where(@created_at >= d).count
674
+ assert_equal 10, User.where(@created_at >= d).count
581
675
  end
582
676
 
583
677
  def test_date_duration
@@ -654,8 +748,10 @@ module ArelExtensions
654
748
  t(@lucas, (@updated_at + Arel.duration('mn', (@updated_at.hour * 60 + @updated_at.minute))))
655
749
 
656
750
  assert_includes ['2024-03-03'], t(@lucas, (@updated_at + durPos).format('%Y-%m-%d'))
751
+ assert_includes ['2024-03-03'], t(@lucas, (@updated_at + durPos).format_date('%Y-%m-%d'))
657
752
  # puts (@updated_at - durPos).to_sql
658
753
  assert_includes ['2004-03-03'], t(@lucas, (@updated_at - durPos).format('%Y-%m-%d'))
754
+ assert_includes ['2004-03-03'], t(@lucas, (@updated_at - durPos).format_date('%Y-%m-%d'))
659
755
 
660
756
 
661
757
  # we test with the ruby object or the string because some adapters don't return an object Date
@@ -690,6 +786,30 @@ module ArelExtensions
690
786
  end
691
787
  end
692
788
 
789
+ def test_if_present
790
+ assert_nil t(@myung, @comments.if_present)
791
+ assert_equal 0, t(@myung, @comments.if_present.count)
792
+ assert_equal 20.16, t(@myung, @score.if_present)
793
+ assert_equal '2016-05-23', t(@myung, @created_at.if_present.format('%Y-%m-%d'))
794
+ assert_equal '2016-05-23', t(@myung, @created_at.if_present.format_date('%Y-%m-%d'))
795
+ assert_nil t(@laure, @comments.if_present)
796
+
797
+ assert_nil t(@nilly, @duration.if_present.format('%Y-%m-%d'))
798
+ assert_nil t(@nilly, @duration.if_present.format_date('%Y-%m-%d'))
799
+
800
+ # NOTE: here we're testing the capacity to format a nil value,
801
+ # however, @comments is a text field, and not a date/datetime field,
802
+ # so Postgres will rightfully complain when we format the text:
803
+ # we need to cast it first.
804
+ if @env_db == 'postgresql'
805
+ assert_nil t(@laure, @comments.cast(:date).if_present.format('%Y-%m-%d'))
806
+ assert_nil t(@laure, @comments.cast(:date).if_present.format_date('%Y-%m-%d'))
807
+ else
808
+ assert_nil t(@laure, @comments.if_present.format('%Y-%m-%d'))
809
+ assert_nil t(@laure, @comments.if_present.format_date('%Y-%m-%d'))
810
+ end
811
+ end
812
+
693
813
  def test_is_null
694
814
  # puts User.where(@age.is_null).select(@name).to_sql
695
815
  # puts @age.is_null
@@ -725,7 +845,7 @@ module ArelExtensions
725
845
  def test_math_minus
726
846
  d = Date.new(2016, 5, 20)
727
847
  # Datediff
728
- assert_equal 9, User.where((@created_at - @created_at).eq(0)).count
848
+ assert_equal 10, User.where((@created_at - @created_at).eq(0)).count
729
849
  assert_equal 3, @laure.select((@created_at - d).as('res')).first.res.abs.to_i
730
850
  # Substraction
731
851
  assert_equal 0, User.where((@age - 10).eq(50)).count
@@ -845,8 +965,8 @@ module ArelExtensions
845
965
 
846
966
  def test_subquery_with_order
847
967
  skip if ['mssql'].include?(@env_db) && Arel::VERSION.to_i < 10
848
- assert_equal 9, User.where(name: User.select(:name).order(:name)).count
849
- assert_equal 9, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
968
+ assert_equal 10, User.where(name: User.select(:name).order(:name)).count
969
+ assert_equal 10, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
850
970
  if !['mysql'].include?(@env_db) # MySql can't have limit in IN subquery
851
971
  assert_equal 2, User.where(name: User.select(:name).order(:name).limit(2)).count
852
972
  # assert_equal 6, User.where(name: User.select(:name).order(:name).offset(2)).count
data/version_v1.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '1.3.5'.freeze
2
+ VERSION = '1.3.7'.freeze
3
3
  end
data/version_v2.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '2.1.5'.freeze
2
+ VERSION = '2.1.7'.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.5
4
+ version: 2.1.7
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-07-25 00:00:00.000000000 Z
13
+ date: 2023-01-27 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,6 +72,7 @@ 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
@@ -94,8 +81,8 @@ files:
94
81
  - arel_extensions.gemspec
95
82
  - functions.html
96
83
  - gemfiles/rails3.gemfile
97
- - gemfiles/rails4.gemfile
98
- - gemfiles/rails5_0.gemfile
84
+ - gemfiles/rails4_2.gemfile
85
+ - gemfiles/rails5.gemfile
99
86
  - gemfiles/rails5_1_4.gemfile
100
87
  - gemfiles/rails5_2.gemfile
101
88
  - gemfiles/rails6.gemfile
@@ -136,6 +123,7 @@ files:
136
123
  - lib/arel_extensions/nodes/find_in_set.rb
137
124
  - lib/arel_extensions/nodes/floor.rb
138
125
  - lib/arel_extensions/nodes/format.rb
126
+ - lib/arel_extensions/nodes/formatted_date.rb
139
127
  - lib/arel_extensions/nodes/formatted_number.rb
140
128
  - lib/arel_extensions/nodes/function.rb
141
129
  - lib/arel_extensions/nodes/is_null.rb
@@ -150,7 +138,9 @@ files:
150
138
  - lib/arel_extensions/nodes/rand.rb
151
139
  - lib/arel_extensions/nodes/repeat.rb
152
140
  - lib/arel_extensions/nodes/replace.rb
141
+ - lib/arel_extensions/nodes/rollup.rb
153
142
  - lib/arel_extensions/nodes/round.rb
143
+ - lib/arel_extensions/nodes/select.rb
154
144
  - lib/arel_extensions/nodes/soundex.rb
155
145
  - lib/arel_extensions/nodes/std.rb
156
146
  - lib/arel_extensions/nodes/substring.rb
@@ -218,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
218
208
  - !ruby/object:Gem::Version
219
209
  version: '0'
220
210
  requirements: []
221
- rubygems_version: 3.2.3
211
+ rubygems_version: 3.3.5
222
212
  signing_key:
223
213
  specification_version: 4
224
214
  summary: Extending Arel