arel_extensions 2.1.5 → 2.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|