-
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
feat: Add support for sum aggregate #121
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #121 +/- ##
===========================================
+ Coverage 63.85% 64.17% +0.31%
===========================================
Files 80 81 +1
Lines 7334 7547 +213
===========================================
+ Hits 4683 4843 +160
- Misses 2165 2208 +43
- Partials 486 496 +10
|
Do you want me to review this code before we talk about some potential architecture changes to the aggregate code? |
Yes please - if I make those changes it will be as part of the next aggregate :) And some of the refactorings here would likely be very useful to have (as well as a 3rd implementation) |
Sounds good, ill jump on it |
3b2e4ce
to
d504c8d
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.
few things, nothing major
c6f67ce
to
c5635d5
Compare
14231d0
to
1655062
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.
some stuff about parsing.
@@ -435,16 +414,31 @@ func parseSelectFields(root SelectionType, fields *ast.SelectionSet) ([]Selectio | |||
|
|||
// parseField simply parses the Name/Alias | |||
// into a Field type | |||
func parseField(root SelectionType, field *ast.Field) *Field { | |||
func parseField(i int, root SelectionType, field *ast.Field) (*Field, 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.
Should we be checking if the field
argument on an aggregate is empty here during the parsing. I know theres an error catch further down the line when you create a aggregate node in the GetAggregateSource
func but at that point theres already tons of work gone into creating the query plan. Would be preferable if we could jump out early if theres that error during parsing, and not plan building.
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 amount of required paths is very specific to the type of aggregate (e.g. _count requires one, and _sum requires 2 unless it is pointed at a scalar array). I'd really rather not leak those implementation details into the shared code
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.
Not sure what you mean by _count
requires one and _sum
requires 2? They both require the field
argument no? Even just the existence of the value is prob good enough, without going into more semantic details. Its formally a parsing validation issue compared to a planning issue.
This is the sumType argument generator, as far as I can see, its only field
, no?
defradb/query/graphql/schema/generate.go
Line 523 in def8d94
"field": newArgConfig(sumType), |
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.
Also, if im understanding correctly, its not really implementation details it they are query spec compliant details.
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.
node implementation details, not defra :) The check is different between count and sum as count needs to reference a list/slice/whatever whereas sum needs to reference a property of a list-item (unless it is a scalar-array). It is not possible to have this in the shared code without the shared code knowing this (e.g. via an if/switch-count/sum/etc or some extra abstract complexity).
2 was a lazy reference to the source variable(s), which needs to be len = 1 for count, and either 1 or two for sum depending on target type.
case string: | ||
path = []string{arguementValue} | ||
case []*ast.ObjectField: | ||
if len(arguementValue) == 0 { | ||
//Note: Scalar arrays will hit this clause and should be handled appropriately (not adding now as not testable in a time-efficient manner) | ||
return fmt.Errorf("Unexpected error: aggregate field contained no child field selector"), PropertyTransformation{} | ||
return []string{}, fmt.Errorf("Unexpected error: aggregate field contained no child field selector") |
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.
See here as a reference for my comment above. We can keep this error check here, but it should be initially checked during parsing, and not planning.
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.
Does the sum system (and I guess the count system) support aggregating values 2 levels deep into a relation? From what I can tell it might only be able to go 1 level deep. I can test on my side, but wanted to ask anyway.
9ee87b8
to
a49f019
Compare
a49f019
to
d58fa51
Compare
d58fa51
to
12adc78
Compare
Makes it easier to share code between aggregates if they are parsed into the same struct
New implementation should happily support other aggregates out of the box
1249da6
to
def8d94
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.
Had a few suggestions about the parser and initFields
stuff. Neither are necessary right now, but id love your thoughts and if theres some consensus then we can make a seperate issue for some small refactoring.
If youd prefer to make the changes now, feel free to, otherwise, im approving this 👍
@@ -435,16 +414,31 @@ func parseSelectFields(root SelectionType, fields *ast.SelectionSet) ([]Selectio | |||
|
|||
// parseField simply parses the Name/Alias | |||
// into a Field type | |||
func parseField(root SelectionType, field *ast.Field) *Field { | |||
func parseField(i int, root SelectionType, field *ast.Field) (*Field, 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.
Not sure what you mean by _count
requires one and _sum
requires 2? They both require the field
argument no? Even just the existence of the value is prob good enough, without going into more semantic details. Its formally a parsing validation issue compared to a planning issue.
This is the sumType argument generator, as far as I can see, its only field
, no?
defradb/query/graphql/schema/generate.go
Line 523 in def8d94
"field": newArgConfig(sumType), |
@@ -435,16 +414,31 @@ func parseSelectFields(root SelectionType, fields *ast.SelectionSet) ([]Selectio | |||
|
|||
// parseField simply parses the Name/Alias | |||
// into a Field type | |||
func parseField(root SelectionType, field *ast.Field) *Field { | |||
func parseField(i int, root SelectionType, field *ast.Field) (*Field, 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.
Also, if im understanding correctly, its not really implementation details it they are query spec compliant details.
break | ||
} | ||
// Join any child collections required by the given transformation if the child collections have not been requested for render by the consumer | ||
func (n *selectNode) joinAggregatedChild(parsed *parser.Select, field *parser.Field) 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.
Another spot where I think it would be cleaner to pass in a parser.AggregateField
instead of just a parser.Field
.
def8d94
to
be59b19
Compare
* Remove unnessecary object deconstruction * Correct count test description * Handle count generation errors * Replace query.Count struct with query.PropertyTransformation Makes it easier to share code between aggregates if they are parsed into the same struct * Generalize aggregate alias magic New implementation should happily support other aggregates out of the box * Move count plan planning to expand aggregate plans function * Extract hidden join logic to generic function * Add support for sum aggregate
Closes #94
Adds support for the summing of child collections of Int and Floats. Also refactors shared aggregated code somewhat (likely to be further altered when adding third aggregate).
Todo: