@@ -318,11 +318,112 @@ def test_offset_is_kept_coerced
318
318
original_test_offset_is_kept
319
319
end
320
320
321
- # Are decimal, not integer.
321
+ # The SQL Server `AVG()` function for a list of integers returns an integer (not a decimal) .
322
322
coerce_tests! :test_should_return_decimal_average_of_integer_field
323
323
def test_should_return_decimal_average_of_integer_field_coerced
324
324
value = Account . average ( :id )
325
- assert_equal BigDecimal ( "3.0" ) . to_s , BigDecimal ( value ) . to_s
325
+ assert_equal 3 , value
326
+ end
327
+
328
+ # In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
329
+ # Match SQL Server limit implementation.
330
+ coerce_tests! :test_select_avg_with_group_by_as_virtual_attribute_with_sql
331
+ def test_select_avg_with_group_by_as_virtual_attribute_with_sql_coerced
332
+ rails_core = companies ( :rails_core )
333
+
334
+ sql = <<~SQL
335
+ SELECT firm_id, AVG(CAST(credit_limit AS DECIMAL)) AS avg_credit_limit
336
+ FROM accounts
337
+ WHERE firm_id = ?
338
+ GROUP BY firm_id
339
+ ORDER BY firm_id
340
+ OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
341
+ SQL
342
+
343
+ account = Account . find_by_sql ( [ sql , rails_core ] ) . first
344
+
345
+ # id was not selected, so it should be nil
346
+ # (cannot select id because it wasn't used in the GROUP BY clause)
347
+ assert_nil account . id
348
+
349
+ # firm_id was explicitly selected, so it should be present
350
+ assert_equal ( rails_core , account . firm )
351
+
352
+ # avg_credit_limit should be present as a virtual attribute
353
+ assert_equal ( 52.5 , account . avg_credit_limit )
354
+ end
355
+
356
+ # In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
357
+ # Order column must be in the GROUP clause.
358
+ coerce_tests! :test_select_avg_with_group_by_as_virtual_attribute_with_ar
359
+ def test_select_avg_with_group_by_as_virtual_attribute_with_ar_coerced
360
+ rails_core = companies ( :rails_core )
361
+
362
+ account = Account
363
+ . select ( :firm_id , "AVG(CAST(credit_limit AS DECIMAL)) AS avg_credit_limit" )
364
+ . where ( firm : rails_core )
365
+ . group ( :firm_id )
366
+ . order ( :firm_id )
367
+ . take!
368
+
369
+ # id was not selected, so it should be nil
370
+ # (cannot select id because it wasn't used in the GROUP BY clause)
371
+ assert_nil account . id
372
+
373
+ # firm_id was explicitly selected, so it should be present
374
+ assert_equal ( rails_core , account . firm )
375
+
376
+ # avg_credit_limit should be present as a virtual attribute
377
+ assert_equal ( 52.5 , account . avg_credit_limit )
378
+ end
379
+
380
+ # In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
381
+ # SELECT columns must be in the GROUP clause.
382
+ # Match SQL Server limit implementation.
383
+ coerce_tests! :test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_sql
384
+ def test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_sql_coerced
385
+ rails_core = companies ( :rails_core )
386
+
387
+ sql = <<~SQL
388
+ SELECT companies.*, AVG(CAST(accounts.credit_limit AS DECIMAL)) AS avg_credit_limit
389
+ FROM companies
390
+ INNER JOIN accounts ON companies.id = accounts.firm_id
391
+ WHERE companies.id = ?
392
+ GROUP BY companies.id, companies.type, companies.firm_id, companies.firm_name, companies.name, companies.client_of, companies.rating, companies.account_id, companies.description
393
+ ORDER BY companies.id
394
+ OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
395
+ SQL
396
+
397
+ firm = DependentFirm . find_by_sql ( [ sql , rails_core ] ) . first
398
+
399
+ # all the DependentFirm attributes should be present
400
+ assert_equal rails_core , firm
401
+ assert_equal rails_core . name , firm . name
402
+
403
+ # avg_credit_limit should be present as a virtual attribute
404
+ assert_equal ( 52.5 , firm . avg_credit_limit )
405
+ end
406
+
407
+
408
+ # In SQL Server the `AVG()` function for a list of integers returns an integer so need to cast values as decimals before averaging.
409
+ # SELECT columns must be in the GROUP clause.
410
+ coerce_tests! :test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_ar
411
+ def test_select_avg_with_joins_and_group_by_as_virtual_attribute_with_ar_coerced
412
+ rails_core = companies ( :rails_core )
413
+
414
+ firm = DependentFirm
415
+ . select ( "companies.*" , "AVG(CAST(accounts.credit_limit AS DECIMAL)) AS avg_credit_limit" )
416
+ . where ( id : rails_core )
417
+ . joins ( :account )
418
+ . group ( :id , :type , :firm_id , :firm_name , :name , :client_of , :rating , :account_id , :description )
419
+ . take!
420
+
421
+ # all the DependentFirm attributes should be present
422
+ assert_equal rails_core , firm
423
+ assert_equal rails_core . name , firm . name
424
+
425
+ # avg_credit_limit should be present as a virtual attribute
426
+ assert_equal ( 52.5 , firm . avg_credit_limit )
326
427
end
327
428
328
429
# Match SQL Server limit implementation
0 commit comments