diff --git a/addon/adapter.go b/addon/adapter.go index 9a989fc8a..492d87e3e 100644 --- a/addon/adapter.go +++ b/addon/adapter.go @@ -38,7 +38,6 @@ type Client = binding.Client type Params = binding.Params type Param = binding.Param type Path = binding.Path -type Field = binding.Field // // Error @@ -60,6 +59,10 @@ type Setting = binding.Setting type Tag = binding.Tag type TagCategory = binding.TagCategory +// +// Filter +type Filter = binding.Filter + // // The Adapter provides hub/addon integration. type Adapter struct { diff --git a/binding/client.go b/binding/client.go index 3722293e4..ca19ed89a 100644 --- a/binding/client.go +++ b/binding/client.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin/binding" liberr "github.com/jortel/go-utils/error" "github.com/konveyor/tackle2-hub/api" + qf "github.com/konveyor/tackle2-hub/binding/filter" "io" "mime/multipart" "net" @@ -36,6 +37,20 @@ type Param struct { Value string } +// +// Filter +type Filter struct { + qf.Filter +} + +// +// Param returns a filter parameter. +func (r *Filter) Param() (p Param) { + p.Key = api.Filter + p.Value = r.String() + return +} + // // Params mapping. type Params map[string]interface{} diff --git a/binding/filter/builder.go b/binding/filter/builder.go new file mode 100644 index 000000000..36c5ac66b --- /dev/null +++ b/binding/filter/builder.go @@ -0,0 +1,173 @@ +package filter + +/* +filter = Filter{} +filter.And("name").Eq("Elmer") +filter.And("age").Gt(10) +filter.And("height").Lt(44) +filter.And("weight").LtEq(150) +filter.And("hair").NotEq("blond") +filter.And("pet").Like("Rov*") +filter.And("friend").Eq(Any{"Sam","Ed"}) +*/ + +import ( + qf "github.com/konveyor/tackle2-hub/api/filter" + "reflect" + "strconv" + "strings" +) + +const ( + EQ = string(qf.EQ) + NOT = string(qf.NOT) + GT = string(qf.GT) + LT = string(qf.LT) + LIKE = string(qf.LIKE) + AND = string(qf.AND) + OR = string(qf.OR) +) + +// +// Any match any. +type Any []interface{} + +// +// All match all. +type All []interface{} + +// +// Filter builder. +type Filter struct { + predicates []*Predicate +} + +// +// And adds a predicate. +// Example: filter.And("name").Equals("Elmer") +func (f *Filter) And(field string) (p *Predicate) { + p = &Predicate{ + field: field, + operator: EQ, + } + f.predicates = append(f.predicates, p) + return p +} + +// +// String returns string representation. +func (f *Filter) String() (s string) { + var preds []string + for _, p := range f.predicates { + preds = append(preds, p.String()) + } + s = strings.Join(preds, string(qf.COMMA)) + return +} + +// +// Predicate is a filter query predicate. +type Predicate struct { + field string + operator string + value string +} + +// +// String returns a string representation of the predicate. +func (p *Predicate) String() (s string) { + s = p.field + p.operator + p.value + return +} + +// +// Eq returns a (=) predicate. +func (p *Predicate) Eq(object interface{}) *Predicate { + p.operator = EQ + p.value = p.valueOf(object) + return p +} + +// +// NotEq returns a (!=) predicate. +func (p *Predicate) NotEq(object interface{}) *Predicate { + p.operator = NOT + EQ + p.value = p.valueOf(object) + return p +} + +// +// Like returns a (~) predicate. +func (p *Predicate) Like(object interface{}) *Predicate { + p.operator = LIKE + p.value = p.valueOf(object) + return p +} + +// +// Gt returns a (>) predicate. +func (p *Predicate) Gt(object interface{}) *Predicate { + p.operator = GT + p.value = p.valueOf(object) + return p +} + +// +// GtEq returns a (>=) predicate. +func (p *Predicate) GtEq(object interface{}) *Predicate { + p.operator = GT + EQ + p.value = p.valueOf(object) + return p +} + +// +// Lt returns a (<) predicate. +func (p *Predicate) Lt(object interface{}) *Predicate { + p.operator = LT + p.value = p.valueOf(object) + return p +} + +// +// LtEq returns a (<) predicate. +func (p *Predicate) LtEq(object interface{}) *Predicate { + p.operator = LT + EQ + p.value = p.valueOf(object) + return p +} + +func (p *Predicate) valueOf(object interface{}) (result string) { + kind := reflect.TypeOf(object).Kind() + value := reflect.ValueOf(object) + switch kind { + case reflect.String: + result = "'" + value.String() + "'" + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + n := value.Int() + result = strconv.Itoa(int(n)) + case reflect.Bool: + result = strconv.FormatBool(value.Bool()) + case reflect.Slice: + var items []string + for i := 0; i < value.Len(); i++ { + item := p.valueOf(value.Index(i).Interface()) + items = append(items, item) + } + var operator string + switch object.(type) { + case Any: + operator = OR + case All: + operator = AND + default: + operator = OR + } + result = strings.Join(items, operator) + result = "(" + result + ")" + } + return +} diff --git a/binding/filter/filter_test.go b/binding/filter/filter_test.go new file mode 100644 index 000000000..6c935e5e0 --- /dev/null +++ b/binding/filter/filter_test.go @@ -0,0 +1,29 @@ +package filter + +import ( + "github.com/onsi/gomega" + "testing" +) + +func TestFilter(t *testing.T) { + g := gomega.NewGomegaWithT(t) + filter := Filter{} + list := Any{"One", "Two", "Three"} + filter.And("name").Eq(list) + p := filter.String() + g.Expect("name=('One'|'Two'|'Three')").To(gomega.Equal(p)) + + filter = Filter{} + filter.And("name").Eq(All{"One", "Two", "Three"}) + p = filter.String() + g.Expect("name=('One','Two','Three')").To(gomega.Equal(p)) + + filter = Filter{} + filter.And("name").Eq("Elmer") + filter.And("age").Gt(10) + filter.And("height").Lt(44) + filter.And("weight").LtEq(150) + filter.And("hair").NotEq("blond") + p = filter.String() + g.Expect("name='Elmer',age>10,height<44,weight<=150,hair!='blond'").To(gomega.Equal(p)) +} diff --git a/binding/ruleset.go b/binding/ruleset.go index 73efc04af..fef167c74 100644 --- a/binding/ruleset.go +++ b/binding/ruleset.go @@ -34,6 +34,14 @@ func (h *RuleSet) List() (list []api.RuleSet, err error) { return } +// +// Find RuleSets with filter. +func (h *RuleSet) Find(filter Filter) (list []api.RuleSet, err error) { + list = []api.RuleSet{} + err = h.client.Get(api.RuleSetsRoot, &list, filter.Param()) + return +} + // // Update a RuleSet. func (h *RuleSet) Update(r *api.RuleSet) (err error) {