-
Notifications
You must be signed in to change notification settings - Fork 116
fix activerecord sum methods #814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@rhiroe Thanks for your contribution! Please follow the instructions below for each change. Available commandsYou can use the following commands by commenting on this PR.
|
I’m a bit confused after receiving a comment outside of the PR that the return value in the case of a block is not necessarily T. |
How about delegating to |
6e4e96d
to
e33cee7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I welcome the accuracy of type information, but not the inconvenience.
It is likely that adjusting the results based on the column type for each model would be the optimal approach, but in most cases, the type would be either Integer
or Float
.
What specific problem does this change solve for you?
def sum: (?untyped? column_name) -> untyped | ||
| [T] () { (Model) -> T } -> (Integer | T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent of my comment was to use overloading.
I don't know if it will work.
def sum: (?untyped? column_name) -> untyped | |
| [T] () { (Model) -> T } -> (Integer | T) | |
def sum: (?untyped? column_name) -> untyped | |
| ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn’t realize that overloading could be used here, but that makes perfect sense. I'll check it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to result in an InvalidOverloadMethodError
. 😢
I agree.
The issue I'm facing is that summing Float values results in an Integer. |
ea5c246
to
34f877d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I generally agree with cases that involve a block.
For cases without a block, let me think about it a bit more.
| () { (Model) -> Integer } -> Integer | ||
def sum: (?untyped? column_name) -> untyped | ||
| [T] () { (Model) -> T } -> (Integer | T) | ||
| [U] (U initial_value) { (Model) -> untyped } -> U |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value does not necessarily match initial_value
.
User.sum(0) { |user| user.decimal_column } #=> BigDecimal
Also, if there are zero records, the type of initial_value seems to be returned.
User.sum(0) { |user| user.decimal_column } #=> Integer(0)
User.sum(0.0) { |user| user.decimal_column } #=> Float(0.0)
If you value practicality,
| [U] (U initial_value) { (Model) -> untyped } -> U | |
| [T] (untyped initial_value) { (Model) -> T } -> T |
If you value accuracy,
| [U] (U initial_value) { (Model) -> untyped } -> U | |
| [T, U] (T initial_value) { (Model) -> U } -> (T | U) |
Here’s my thought on cases without a block: In conclusion, I believe To express it completely accurately, the class User < ActiveRecord::Base
def self.sum: (:id) -> Integer
| (:hight) -> Float
| ...
end A simpler approach would be to use However, neither seems particularly convenient to me. sum_of_hight = User.sum(:hight) #: Float Therefore, I think For cases with a block and an |
Thank you for your suggestion. +1. I believe the type for cases with Therefore, I’m considering defining the type as follows: def sum: (?untyped? column_name) -> untyped
| [T] (?T initial_value) { (Model) -> T } -> T At this point, I don’t see the need to differentiate the type based on the presence of This is my current thought on the matter. What do you think? |
|
34f877d
to
c9ad1f5
Compare
When a block is given, it is delegated to Enumerable#sum. See `Enumerable#sum` for reference. Since it is more type-friendly for the types of `initial_value`, the block's return value, and the method's return value to match, I will accept some imprecision and unify all types as `T`. When no block is given, the calculate method processes the result, so the return value is not necessarily an Integer. https://github.com/rails/rails/blob/v6.0.6.1/activerecord/lib/active_record/relation/calculations.rb#L127
0c805ab
to
6bc88df
Compare
@rhiroe Thanks for your contribution! Please follow the instructions below for each change. Available commandsYou can use the following commands by commenting on this PR.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
APPROVE
/merge |
When a block is given, it is delegated to Enumerable#sum. See
Enumerable#sum
for reference.Since it is more type-friendly for the types of
initial_value
, the block's return value, and the method's return value to match, I will accept some imprecision and unify all types asT
.When no block is given, the calculate method processes the result, so the return value is not necessarily an Integer.
https://github.com/rails/rails/blob/v6.0.6.1/activerecord/lib/active_record/relation/calculations.rb#L127