-
Notifications
You must be signed in to change notification settings - Fork 9
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 is empty, is not empty, starts with, ends with filters operators #801
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,12 @@ import ( | |
"github.com/checkmarble/marble-backend/models/ast" | ||
) | ||
|
||
// Define where to put that | ||
type FilterWithType struct { | ||
Filter ast.Filter | ||
FieldType models.DataType | ||
} | ||
|
||
type IngestedDataReadRepository interface { | ||
GetDbField(ctx context.Context, exec Executor, readParams models.DbFieldReadParams) (any, error) | ||
ListAllObjectIdsFromTable( | ||
|
@@ -33,7 +39,7 @@ type IngestedDataReadRepository interface { | |
fieldName string, | ||
fieldType models.DataType, | ||
aggregator ast.Aggregator, | ||
filters []ast.Filter, | ||
filters []FilterWithType, | ||
) (any, error) | ||
} | ||
|
||
|
@@ -314,7 +320,7 @@ func createQueryAggregated( | |
fieldName string, | ||
fieldType models.DataType, | ||
aggregator ast.Aggregator, | ||
filters []ast.Filter, | ||
filters []FilterWithType, | ||
) (squirrel.SelectBuilder, error) { | ||
var selectExpression string | ||
if aggregator == ast.AGGREGATOR_COUNT_DISTINCT { | ||
|
@@ -339,7 +345,8 @@ func createQueryAggregated( | |
|
||
var err error | ||
for _, filter := range filters { | ||
query, err = addConditionForOperator(query, qualifiedTableName, filter.FieldName, filter.Operator, filter.Value) | ||
query, err = addConditionForOperator(query, qualifiedTableName, | ||
filter.Filter.FieldName, filter.FieldType, filter.Filter.Operator, filter.Filter.Value) | ||
if err != nil { | ||
return squirrel.SelectBuilder{}, err | ||
} | ||
|
@@ -354,7 +361,7 @@ func (repo *IngestedDataReadRepositoryImpl) QueryAggregatedValue( | |
fieldName string, | ||
fieldType models.DataType, | ||
aggregator ast.Aggregator, | ||
filters []ast.Filter, | ||
filters []FilterWithType, | ||
) (any, error) { | ||
if err := validateClientDbExecutor(exec); err != nil { | ||
return nil, err | ||
|
@@ -377,7 +384,7 @@ func (repo *IngestedDataReadRepositoryImpl) QueryAggregatedValue( | |
return result, nil | ||
} | ||
|
||
func addConditionForOperator(query squirrel.SelectBuilder, tableName string, fieldName string, | ||
func addConditionForOperator(query squirrel.SelectBuilder, tableName string, fieldName string, fieldType models.DataType, | ||
operator ast.FilterOperator, value any, | ||
) (squirrel.SelectBuilder, error) { | ||
switch operator { | ||
|
@@ -393,6 +400,30 @@ func addConditionForOperator(query squirrel.SelectBuilder, tableName string, fie | |
return query.Where(squirrel.Lt{fmt.Sprintf("%s.%s", tableName, fieldName): value}), nil | ||
case ast.FILTER_LESSER_OR_EQUAL: | ||
return query.Where(squirrel.LtOrEq{fmt.Sprintf("%s.%s", tableName, fieldName): value}), nil | ||
case ast.FILTER_IS_EMPTY: | ||
orCondition := squirrel.Or{ | ||
squirrel.Eq{fmt.Sprintf("%s.%s", tableName, fieldName): nil}, | ||
} | ||
if fieldType == models.String { | ||
orCondition = append(orCondition, squirrel.Eq{ | ||
fmt.Sprintf("%s.%s", tableName, fieldName): "", | ||
}) | ||
} | ||
return query.Where(orCondition), nil | ||
case ast.FILTER_IS_NOT_EMPTY: | ||
andCondition := squirrel.And{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can reduce code a little bit by avoiding the squirrel.And and just adding to the squirrel.NotEq conditionally There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That may be a stupid question, but I don't know how I can add the second NotEq conditionally on the first one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. squirrel.And is just an alias wrapper over a go map[string]any, so just by setting the value in the map There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I read the code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sorry, I didn't write what I meant to write. I meant to say that squirrel.(Not)Eq is a wrapper over a map. notEq := squirrel.NotEq{fmt.Sprintf("%s.%s", tableName, fieldName): nil}
if fieldType == models.String {
notEq[fmt.Sprintf("%s.%s", tableName, fieldName)] = ""
}
return query.Where(notEq), nil There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh but won't the second one replace the first? The key being the same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok you are right 🤦 sorry for misleading you |
||
squirrel.NotEq{fmt.Sprintf("%s.%s", tableName, fieldName): nil}, | ||
} | ||
if fieldType == models.String { | ||
andCondition = append(andCondition, | ||
squirrel.NotEq{fmt.Sprintf("%s.%s", tableName, fieldName): ""}, | ||
) | ||
} | ||
return query.Where(andCondition), nil | ||
case ast.FILTER_STARTS_WITH: | ||
return query.Where(squirrel.Like{fmt.Sprintf("%s.%s", tableName, fieldName): fmt.Sprintf("%s%%", value)}), nil | ||
case ast.FILTER_ENDS_WITH: | ||
return query.Where(squirrel.Like{fmt.Sprintf("%s.%s", tableName, fieldName): fmt.Sprintf("%%%s", value)}), nil | ||
default: | ||
return query, fmt.Errorf("unknown operator %s: %w", operator, models.BadParameterError) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,10 @@ var validTypeForFilterOperators = map[ast.FilterOperator][]models.DataType{ | |
ast.FILTER_LESSER_OR_EQUAL: {models.Int, models.Float, models.String, models.Timestamp}, | ||
ast.FILTER_IS_IN_LIST: {models.String}, | ||
ast.FILTER_IS_NOT_IN_LIST: {models.String}, | ||
ast.FILTER_IS_EMPTY: {models.Int, models.Float, models.String, models.Timestamp}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just for the sake of completeness: could also work with bool type |
||
ast.FILTER_IS_NOT_EMPTY: {models.Int, models.Float, models.String, models.Timestamp}, | ||
ast.FILTER_STARTS_WITH: {models.String}, | ||
ast.FILTER_ENDS_WITH: {models.String}, | ||
} | ||
|
||
func (f FilterEvaluator) Evaluate(ctx context.Context, arguments ast.Arguments) (any, []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.
Prefer to put it into models (most generally) or optionally in the usecase where you are using it (if it's really a local type that you'll use just there)
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.
=> in this case, into models since you use it in the usecase and the repo