-
Notifications
You must be signed in to change notification settings - Fork 51
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
refactor: Rework sum and count nodes to make use of generics #757
refactor: Rework sum and count nodes to make use of generics #757
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #757 +/- ##
===========================================
+ Coverage 58.02% 58.07% +0.04%
===========================================
Files 144 144
Lines 16593 16578 -15
===========================================
- Hits 9628 9627 -1
+ Misses 6052 6043 -9
+ Partials 913 908 -5
|
@@ -99,62 +99,28 @@ func (n *countNode) Next() (bool, error) { | |||
// v.Len will panic if v is not one of these types, we don't want it to panic | |||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: | |||
if source.Filter != nil { | |||
var arrayCount int | |||
var err error | |||
switch array := property.(type) { |
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.
question: Wondering if there is a possibility to replace all the cases with:
case []core.Doc, []bool, []int64, []float64, []string:
arrayCount, err = countItems(array, source.Filter)
}
Type inference issue?
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.
Yeah, some langs let you do that but I couldn't find a way in Go (including in the reflect package in case they'd added some generic funcs) - would have been nice
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.
If not possible then don't worry about it. Still makes things a lot nicer than before.
query/graphql/planner/count.go
Outdated
@@ -165,4 +131,18 @@ func (n *countNode) Next() (bool, error) { | |||
return true, nil | |||
} | |||
|
|||
func countItems[T any](collection []T, filter *mapper.Filter) (int, error) { |
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.
suggestion: Define the type constraint rather than using any
.
func countItems[T any](collection []T, filter *mapper.Filter) (int, error) { | |
type Countable interface { | |
core.Doc | ~bool | ~int64 | ~float64 | ~string | |
} | |
func countItems[T Countable](collection []T, filter *mapper.Filter) (int, error) { |
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.
Why? This function will work with any type of 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.
Is that the desired behavior? thought we specifically wanted to only handle the cases defined in the switches and any other element type is to be treated like any error or default case.
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.
Yes it is desired. Why would you block future cases and couple the function to specific types?
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.
Well it's normal to want to limit some functionality for a specific unsupported type, I was wondering if perhaps the reason we had explicit cases was maybe that we wanted to limit count/sum only to these cases. However, I understand now that we need the explicit cases because we need the actual type information instead of interface{}
(through type switch).
As this is desired (and assuming also desired for the sum items), this is resolved.
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.
Quick thought regarding type constraints to simplify sum
query/graphql/planner/sum.go
Outdated
@@ -257,4 +242,19 @@ func (n *sumNode) Next() (bool, error) { | |||
return true, nil | |||
} | |||
|
|||
func sumItems[T any](collection []T, filter *mapper.Filter, toFloat func(T) float64) (float64, error) { |
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.
suggestion: Instead of using T any
we can limit the type constraint to "numbers"
eg
import "golang.org/x/exp/constraints"
type Number interface {
constraints.Integer | constraint.Float
}
Then you wouldn't have to do toFloat
, then you can convert the final results sum
into a float64 return float64(sum)
and since sum is guranteed to be a number, the compiler will be happy with that conversion. So you can drop the argument dependancy entirely
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.
toFloat also takes child documents, not just numbers - what you are suggesting is not possible without reverting 1 out of the 3 current cases
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.
Lol, I wanted to scream when I read 'golang.org/x/exp/constraints' - Golang really really loves doing stuff that is known at compile time at runtime... Why would you want to box values of the generic type?? (I assume at least given that it is an interface)
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.
Its not really box values of generic types, theres a new special syntax for type constraints that re-uses the interface semantics
ie
type Number interface {
~int
}
is special type constraint attached to the named interface Number
.
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.
As for sub documents, wouldn't it make sense to do the subdoc stuff outside of sumItems
? Since the toFloat
function for []code.Doc
does child-access stuff, and also uses index contexts outside of its scope. Seems simipler to seperate the two, and not have the toFloat
func.
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.
theres a new special syntax for type constraints that re-uses the interface semantics
Ah okay, and I checked - it doesn't seem to behave like a pointer either, bit odd to use interface for that though - looks like you can't use them as interfaces either (compiler blocks it)
As for sub documents, wouldn't it make sense to do the subdoc stuff outside of sumItems?
I didn't think so when I wrote it, I would rather have everything go through the same logic and keep as much as possible out of the switch. Would also prefer to leave the function unconstrained - reduces the risk of having to change it in the future
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.
:) Now I'm hopeful for unions lol (if not rust-style enums)
query/graphql/planner/count.go
Outdated
@@ -165,4 +131,18 @@ func (n *countNode) Next() (bool, error) { | |||
return true, nil | |||
} | |||
|
|||
func countItems[T any](collection []T, filter *mapper.Filter) (int, error) { |
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.
extreme nitpick: change parameter name from collection
as its used a lot in a specific context (ie collections in the DB) :)
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.
lol, fair enough, will do
- rename param (and for sum)
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.
LGTM.
4a5714c
to
e862f65
Compare
coversations appear resolved and I need this code in to progress on the more important task - any comments you may add here can be applied to that branch
…etwork#757) * Refactor count node to make use of generics * Refactor sum node to make use of generics
Relevant issue(s)
Resolves #633
Description
Rework sum and count node type switches to make use of generics. Switches changed in this PR will be expanded with new cases shortly and I'd rather not write them twice :)
Specify the platform(s) on which this was tested: