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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +156 -153
- data/NEWS.md +32 -0
- data/README.md +151 -83
- data/appveyor.yml +9 -0
- data/arel_extensions.gemspec +0 -1
- data/gemfiles/{rails4.gemfile → rails4_2.gemfile} +12 -3
- data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +0 -0
- data/gemfiles/rails6_1.gemfile +1 -1
- data/gemfiles/rails7.gemfile +1 -1
- data/gemspecs/arel_extensions-v1.gemspec +0 -1
- data/gemspecs/arel_extensions-v2.gemspec +0 -1
- data/lib/arel_extensions/date_duration.rb +5 -0
- data/lib/arel_extensions/nodes/case.rb +4 -3
- data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
- data/lib/arel_extensions/nodes/rollup.rb +36 -0
- data/lib/arel_extensions/nodes/select.rb +10 -0
- data/lib/arel_extensions/null_functions.rb +16 -0
- data/lib/arel_extensions/string_functions.rb +1 -0
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +97 -0
- data/lib/arel_extensions/visitors/mysql.rb +89 -21
- data/lib/arel_extensions/visitors/oracle.rb +21 -0
- data/lib/arel_extensions/visitors/postgresql.rb +4 -0
- data/lib/arel_extensions/visitors/to_sql.rb +20 -0
- data/lib/arel_extensions/visitors.rb +8 -0
- data/lib/arel_extensions.rb +16 -0
- data/test/with_ar/all_agnostic_test.rb +249 -129
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +9 -19
@@ -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
|
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
|
342
|
+
assert_equal 8, User.where(@name !~ '^L').count
|
298
343
|
assert_equal 1, User.where(@name =~ /^M/).count
|
299
|
-
assert_equal
|
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
|
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
|
332
|
-
assert_equal
|
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
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
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
|
-
|
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
|
-
|
432
|
-
|
433
|
-
|
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
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
assert_equal '
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
assert_equal '
|
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
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
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
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
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
|
-
|
490
|
-
|
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
|
-
|
494
|
-
|
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
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
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
|
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
|
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
|
849
|
-
assert_equal
|
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
data/version_v2.rb
CHANGED
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
|
+
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:
|
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/
|
98
|
-
- gemfiles/
|
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.
|
211
|
+
rubygems_version: 3.3.5
|
222
212
|
signing_key:
|
223
213
|
specification_version: 4
|
224
214
|
summary: Extending Arel
|