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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +162 -222
- data/.gitignore +7 -6
- data/.rubocop.yml +37 -0
- data/Gemfile +3 -3
- data/NEWS.md +15 -0
- data/README.md +119 -75
- data/appveyor.yml +82 -0
- data/arel_extensions.gemspec +0 -1
- data/gemfiles/rails3.gemfile +5 -5
- data/gemfiles/rails4_2.gemfile +38 -0
- data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +6 -6
- data/gemfiles/rails5_1_4.gemfile +6 -6
- data/gemfiles/rails5_2.gemfile +6 -5
- data/gemfiles/rails6.gemfile +5 -4
- data/gemfiles/rails6_1.gemfile +5 -4
- data/gemfiles/rails7.gemfile +5 -4
- data/gemspecs/arel_extensions-v1.gemspec +0 -1
- data/gemspecs/arel_extensions-v2.gemspec +0 -1
- data/lib/arel_extensions/common_sql_functions.rb +2 -2
- data/lib/arel_extensions/helpers.rb +12 -12
- data/lib/arel_extensions/math.rb +32 -17
- data/lib/arel_extensions/nodes/case.rb +4 -3
- data/lib/arel_extensions/nodes/cast.rb +2 -2
- data/lib/arel_extensions/nodes/coalesce.rb +1 -1
- data/lib/arel_extensions/nodes/collate.rb +1 -1
- data/lib/arel_extensions/nodes/date_diff.rb +6 -6
- data/lib/arel_extensions/nodes/locate.rb +1 -1
- data/lib/arel_extensions/nodes/repeat.rb +2 -2
- data/lib/arel_extensions/nodes/rollup.rb +36 -0
- data/lib/arel_extensions/nodes/select.rb +10 -0
- data/lib/arel_extensions/nodes/substring.rb +1 -1
- data/lib/arel_extensions/nodes/then.rb +1 -1
- data/lib/arel_extensions/nodes/trim.rb +2 -2
- data/lib/arel_extensions/nodes/union.rb +3 -3
- data/lib/arel_extensions/nodes/union_all.rb +2 -2
- 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/ibm_db.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +123 -17
- data/lib/arel_extensions/visitors/mysql.rb +78 -11
- data/lib/arel_extensions/visitors/oracle.rb +39 -17
- data/lib/arel_extensions/visitors/postgresql.rb +17 -12
- data/lib/arel_extensions/visitors/sqlite.rb +4 -4
- data/lib/arel_extensions/visitors/to_sql.rb +4 -1
- data/lib/arel_extensions/visitors.rb +8 -0
- data/lib/arel_extensions.rb +26 -0
- data/test/arelx_test_helper.rb +1 -1
- data/test/real_db_test.rb +5 -5
- data/test/support/fake_record.rb +1 -1
- data/test/visitors/test_bulk_insert_oracle.rb +3 -3
- data/test/visitors/test_bulk_insert_sqlite.rb +1 -1
- data/test/visitors/test_bulk_insert_to_sql.rb +1 -1
- data/test/visitors/test_to_sql.rb +6 -6
- data/test/with_ar/all_agnostic_test.rb +177 -70
- data/test/with_ar/insert_agnostic_test.rb +3 -3
- data/test/with_ar/test_bulk_sqlite.rb +1 -1
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +8 -18
- 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
|
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: [
|
197
|
-
assert_equal 'Lucas,Sophie', t(User.where(name: [
|
198
|
-
assert_equal 'Lucas,Sophie', t(User.where(name: [
|
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: [
|
202
|
-
assert_equal 'Sophie,Lucas,Arthur', t(User.where(name: [
|
203
|
-
assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: [
|
204
|
-
assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: [
|
205
|
-
assert_equal 'Lucas,Sophie,Arthur', t(User.where(name: [
|
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
|
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,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
|
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', {
|
428
|
-
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {
|
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', {
|
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', {
|
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', {
|
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', {
|
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 [
|
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 [
|
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' => {
|
495
|
-
'mysql' => {
|
496
|
-
'postgresql' => {
|
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
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
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
|
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 *
|
606
|
-
assert_equal(-3600 *
|
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
|
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(/
|
666
|
-
assert_equal '20.161', t(@laure, @score.cast(:string) + 1).gsub(/
|
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
|
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(
|
751
|
-
assert_equal 3, User.find_by_sql(
|
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 +
|
790
|
-
assert_equal '123456765,6', t(@arthur, (@score +
|
791
|
-
assert_equal '123,456,765.6', t(@arthur, (@score +
|
792
|
-
assert_equal ' 123,456,765.6', t(@arthur, (@score +
|
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
|
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
|
842
|
-
assert_equal
|
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 [
|
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 [
|
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
|
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
|
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 || [
|
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' => [
|
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' => [
|
990
|
-
assert_equal ({'Arthur' => [
|
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 = [
|
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 = [
|
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
|
-
[
|
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 = [
|
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
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.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-
|
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/
|
97
|
-
- gemfiles/
|
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
|
data/gemfiles/rails4.gemfile
DELETED
@@ -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: '../'
|