diff --git a/flyteadmin/pkg/common/filters.go b/flyteadmin/pkg/common/filters.go index 081d8ea95b..a5974fb286 100644 --- a/flyteadmin/pkg/common/filters.go +++ b/flyteadmin/pkg/common/filters.go @@ -29,6 +29,7 @@ const ( Equal NotEqual ValueIn + ValueNotIn ) // String formats for various filter expression queries @@ -43,6 +44,7 @@ const ( equalQuery = "%s = ?" notEqualQuery = "%s <> ?" valueInQuery = "%s in (?)" + valueNotInQuery = "%s not in (?)" ) // Set of available filters which exclusively accept a single argument value. @@ -58,7 +60,8 @@ var singleValueFilters = map[FilterExpression]bool{ // Set of available filters which exclusively accept repeated argument values. var repeatedValueFilters = map[FilterExpression]bool{ - ValueIn: true, + ValueIn: true, + ValueNotIn: true, } const EqualExpression = "eq" @@ -72,6 +75,19 @@ var filterNameMappings = map[string]FilterExpression{ EqualExpression: Equal, "ne": NotEqual, "value_in": ValueIn, + "value_not_in": ValueNotIn, +} + +var filterQueryMappings = map[FilterExpression]string{ + Contains: containsQuery, + GreaterThan: greaterThanQuery, + GreaterThanOrEqual: greaterThanOrEqualQuery, + LessThan: lessThanQuery, + LessThanOrEqual: lessThanOrEqualQuery, + Equal: equalQuery, + NotEqual: notEqualQuery, + ValueIn: valueInQuery, + ValueNotIn: valueNotInQuery, } var executionIdentifierFields = map[string]bool{ @@ -108,6 +124,8 @@ func getFilterExpressionName(expression FilterExpression) string { return "not equal" case ValueIn: return "value in" + case ValueNotIn: + return "value not in" default: return "" } @@ -166,9 +184,9 @@ func (f *inlineFilterImpl) GetField() string { func (f *inlineFilterImpl) getGormQueryExpr(formattedField string) (GormQueryExpr, error) { - // ValueIn is special because it uses repeating values. - if f.function == ValueIn { - queryStr := fmt.Sprintf(valueInQuery, formattedField) + // Filters that use repeated values + if _, ok := repeatedValueFilters[f.function]; ok { + queryStr := fmt.Sprintf(filterQueryMappings[f.function], formattedField) return GormQueryExpr{ Query: queryStr, Args: f.repeatedValue, diff --git a/flyteadmin/pkg/common/filters_test.go b/flyteadmin/pkg/common/filters_test.go index e49084557f..32fd776c9e 100644 --- a/flyteadmin/pkg/common/filters_test.go +++ b/flyteadmin/pkg/common/filters_test.go @@ -1,6 +1,7 @@ package common import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -83,6 +84,14 @@ func TestNewRepeatedValueFilter(t *testing.T) { assert.Equal(t, "projects.project in (?)", expression.Query) assert.Equal(t, vals, expression.Args) + filter, err = NewRepeatedValueFilter(Workflow, ValueNotIn, "project", vals) + assert.NoError(t, err) + + expression, err = filter.GetGormJoinTableQueryExpr("projects") + assert.NoError(t, err) + assert.Equal(t, "projects.project not in (?)", expression.Query) + assert.Equal(t, vals, expression.Args) + _, err = NewRepeatedValueFilter(Workflow, Equal, "domain", []string{"production", "qa"}) assert.EqualError(t, err, "invalid repeated value filter expression: equal") } @@ -96,16 +105,6 @@ func TestGetGormJoinTableQueryExpr(t *testing.T) { assert.Equal(t, "workflows.domain = ?", gormQueryExpr.Query) } -var expectedQueriesForFilters = map[FilterExpression]string{ - Contains: "field LIKE ?", - GreaterThan: "field > ?", - GreaterThanOrEqual: "field >= ?", - LessThan: "field < ?", - LessThanOrEqual: "field <= ?", - Equal: "field = ?", - NotEqual: "field <> ?", -} - var expectedArgsForFilters = map[FilterExpression]string{ Contains: "%value%", GreaterThan: "value", @@ -117,12 +116,13 @@ var expectedArgsForFilters = map[FilterExpression]string{ } func TestQueryExpressions(t *testing.T) { - for expression, expectedQuery := range expectedQueriesForFilters { + for expression, _ := range singleValueFilters { filter, err := NewSingleValueFilter(Workflow, expression, "field", "value") assert.NoError(t, err) gormQueryExpr, err := filter.GetGormQueryExpr() assert.NoError(t, err) + expectedQuery := fmt.Sprintf(filterQueryMappings[expression], "field") assert.Equal(t, expectedQuery, gormQueryExpr.Query) expectedArg, ok := expectedArgsForFilters[expression] @@ -130,14 +130,17 @@ func TestQueryExpressions(t *testing.T) { assert.Equal(t, expectedArg, gormQueryExpr.Args) } - // Also test the one repeated value filter - filter, err := NewRepeatedValueFilter(Workflow, ValueIn, "field", []string{"value"}) - assert.NoError(t, err) + // Also test the repeated value filters + for expression, _ := range repeatedValueFilters { + filter, err := NewRepeatedValueFilter(Workflow, expression, "field", []string{"value"}) + assert.NoError(t, err) - gormQueryExpr, err := filter.GetGormQueryExpr() - assert.NoError(t, err) - assert.Equal(t, "field in (?)", gormQueryExpr.Query) - assert.EqualValues(t, []string{"value"}, gormQueryExpr.Args) + gormQueryExpr, err := filter.GetGormQueryExpr() + assert.NoError(t, err) + expectedQuery := fmt.Sprintf(filterQueryMappings[expression], "field") + assert.Equal(t, expectedQuery, gormQueryExpr.Query) + assert.EqualValues(t, []string{"value"}, gormQueryExpr.Args) + } } func TestMapFilter(t *testing.T) {