Skip to content
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

Merged
merged 8 commits into from
Jan 30, 2022
Merged

Conversation

AndrewSisley
Copy link
Contributor

@AndrewSisley AndrewSisley commented Jan 17, 2022

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:

@AndrewSisley AndrewSisley added feature New feature or request area/query Related to the query component labels Jan 17, 2022
@AndrewSisley AndrewSisley self-assigned this Jan 17, 2022
@codecov
Copy link

codecov bot commented Jan 17, 2022

Codecov Report

Merging #121 (def8d94) into develop (d0ba8d4) will increase coverage by 0.31%.
The diff coverage is 78.77%.

❗ Current head def8d94 differs from pull request most recent head be59b19. Consider uploading reports for the commit be59b19 to get more accurate results
Impacted file tree graph

@@             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     
Impacted Files Coverage Δ
db/tests/query/simple/utils.go 100.00% <ø> (ø)
query/graphql/parser/commit.go 59.61% <ø> (-7.06%) ⬇️
query/graphql/planner/sum.go 72.54% <72.54%> (ø)
query/graphql/planner/count.go 81.57% <78.57%> (-3.61%) ⬇️
query/graphql/planner/select.go 77.29% <79.10%> (+0.56%) ⬆️
query/graphql/schema/generate.go 82.35% <81.25%> (-0.43%) ⬇️
query/graphql/parser/query.go 74.68% <85.36%> (+0.23%) ⬆️
query/graphql/planner/planner.go 73.20% <100.00%> (+0.43%) ⬆️
... and 3 more

@jsimnz
Copy link
Member

jsimnz commented Jan 19, 2022

Do you want me to review this code before we talk about some potential architecture changes to the aggregate code?

@AndrewSisley
Copy link
Contributor Author

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)

@jsimnz
Copy link
Member

jsimnz commented Jan 19, 2022

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

Copy link
Member

@jsimnz jsimnz left a 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

query/graphql/schema/generate.go Show resolved Hide resolved
db/tests/query/inline_array/with_sum_test.go Show resolved Hide resolved
query/graphql/parser/query.go Outdated Show resolved Hide resolved
query/graphql/parser/query.go Outdated Show resolved Hide resolved
query/graphql/parser/query.go Show resolved Hide resolved
query/graphql/planner/planner.go Outdated Show resolved Hide resolved
query/graphql/planner/planner.go Outdated Show resolved Hide resolved
query/graphql/planner/select.go Outdated Show resolved Hide resolved
query/graphql/planner/sum.go Outdated Show resolved Hide resolved
@AndrewSisley AndrewSisley force-pushed the sisley/feat/I94-sum branch 11 times, most recently from c6f67ce to c5635d5 Compare January 25, 2022 22:48
@AndrewSisley AndrewSisley force-pushed the sisley/feat/I94-sum branch 3 times, most recently from 14231d0 to 1655062 Compare January 25, 2022 23:00
Copy link
Member

@jsimnz jsimnz left a 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) {
Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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?

"field": newArgConfig(sumType),

Copy link
Member

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.

Copy link
Contributor Author

@AndrewSisley AndrewSisley Jan 30, 2022

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")
Copy link
Member

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.

query/graphql/planner/select.go Outdated Show resolved Hide resolved
Copy link
Member

@jsimnz jsimnz left a 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.

@AndrewSisley AndrewSisley force-pushed the sisley/feat/I94-sum branch 2 times, most recently from 1249da6 to def8d94 Compare January 27, 2022 23:01
Copy link
Member

@jsimnz jsimnz left a 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) {
Copy link
Member

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?

"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) {
Copy link
Member

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.

query/graphql/parser/query.go Show resolved Hide resolved
query/graphql/planner/count.go Show resolved Hide resolved
query/graphql/planner/select.go Show resolved Hide resolved
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 {
Copy link
Member

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.

@AndrewSisley AndrewSisley merged commit 8c4cc7e into develop Jan 30, 2022
@AndrewSisley AndrewSisley deleted the sisley/feat/I94-sum branch January 30, 2022 23:34
shahzadlone pushed a commit to shahzadlone/defradb that referenced this pull request Feb 23, 2024
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/query Related to the query component feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Aggregate: Sum
2 participants