diff --git a/structmatcher/README.md b/structmatcher/README.md index 6220a301d..6f5539eed 100644 --- a/structmatcher/README.md +++ b/structmatcher/README.md @@ -20,7 +20,9 @@ Available operators: - *exp: expired - *or: logical or - *and: logical and +- *not: logical not - *has: receives a list of elements and checks that the elements are present in the specified field (StringMap type) +- *rsr: will apply a rsr check to the field (see utils/rsrfield.go) Equal (*eq) and local and (*and) operators are implicit for shortcuts. In this way: diff --git a/structmatcher/structmatcher.go b/structmatcher/structmatcher.go index 419e23095..50cfa37ca 100644 --- a/structmatcher/structmatcher.go +++ b/structmatcher/structmatcher.go @@ -16,7 +16,9 @@ Available operators: - *exp: expired - *or: logical or - *and: logical and +- *not: logical not - *has: receives a list of elements and checks that the elements are present in the specified field (StringMap type) +- *rsr: will apply a rsr check to the field (see utils/rsrfield.go) Equal (*eq) and local and (*and) operators are implicit for shortcuts. In this way: @@ -43,6 +45,7 @@ const ( CondEXP = "*exp" CondOR = "*or" CondAND = "*and" + CondNOT = "*not" CondHAS = "*has" CondRSR = "*rsr" ) @@ -177,7 +180,7 @@ func (os *operatorSlice) checkStruct(o interface{}) (bool, error) { return true, nil } } - case CondAND: + case CondAND, CondNOT: accumulator := true for _, cond := range os.slice { check, err := cond.checkStruct(o) @@ -186,7 +189,11 @@ func (os *operatorSlice) checkStruct(o interface{}) (bool, error) { } accumulator = accumulator && check } - return accumulator, nil + if os.operator == CondAND { + return accumulator, nil + } else { + return !accumulator, nil + } } return false, nil } diff --git a/structmatcher/structmatcher_test.go b/structmatcher/structmatcher_test.go index e221d1272..e4a30c51e 100644 --- a/structmatcher/structmatcher_test.go +++ b/structmatcher/structmatcher_test.go @@ -95,6 +95,13 @@ func TestStructMatcherKeyValue(t *testing.T) { if check, err := cl.Match(o); !check || err != nil { t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) } + err = cl.Parse(`{"*not":[{"Other":true, "Field":{"*gt":5}}]}`) + if err != nil { + t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err) + } + if check, err := cl.Match(o); check || err != nil { + t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) + } err = cl.Parse(`{"Other":true, "Field":{"*gt":7}}`) if err != nil { t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err) @@ -345,6 +352,13 @@ func TestStructMatcherOperatorSlice(t *testing.T) { if check, err := cl.Match(o); !check || err != nil { t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) } + err = cl.Parse(`{"*not":[{"*or":[{"Test":"test"},{"Field":{"*gt":7}},{"Other":false}]}]}`) + if err != nil { + t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err) + } + if check, err := cl.Match(o); check || err != nil { + t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) + } err = cl.Parse(`{"*and":[{"Test":"test"},{"Field":{"*gt":5}},{"Other":true}]}`) if err != nil { t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err) @@ -352,6 +366,13 @@ func TestStructMatcherOperatorSlice(t *testing.T) { if check, err := cl.Match(o); !check || err != nil { t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) } + err = cl.Parse(`{"*not":[{"*and":[{"Test":"test"},{"Field":{"*gt":5}},{"Other":true}]}]}`) + if err != nil { + t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err) + } + if check, err := cl.Match(o); check || err != nil { + t.Errorf("Error checking struct: %v %v (%v)", check, err, toJSON(cl.rootElement)) + } err = cl.Parse(`{"*and":[{"Test":"test"},{"Field":{"*gt":7}},{"Other":false}]}`) if err != nil { t.Errorf("Error loading structure: %+v (%v)", toJSON(cl.rootElement), err)