@@ -318,11 +318,112 @@ def test_offset_is_kept_coerced
318318 original_test_offset_is_kept
319319 end
320320
321- # Are decimal, not integer.
321+ # The SQL Server `AVG()` function for a list of integers returns an integer (not a decimal) .
322322 coerce_tests! :test_should_return_decimal_average_of_integer_field
323323 def test_should_return_decimal_average_of_integer_field_coerced
324324 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 )
326427 end
327428
328429 # Match SQL Server limit implementation
0 commit comments