func operateStrings(op lex.Token, av, bv value.StringValue) value.Value { // Any other ops besides eq/not ? a, b := av.Val(), bv.Val() switch op.T { case lex.TokenEqualEqual, lex.TokenEqual: // == //u.Infof("==? %v %v", av, bv) if a == b { return value.BoolValueTrue } return value.BoolValueFalse case lex.TokenNE: // != //u.Infof("!=? %v %v", av, bv) if a == b { return value.BoolValueFalse } return value.BoolValueTrue case lex.TokenLike: // a(value) LIKE b(pattern) match, err := glob.Match(b, a) if err != nil { value.NewErrorValuef("invalid LIKE pattern: %q", a) } if match { return value.BoolValueTrue } return value.BoolValueFalse } return value.NewErrorValuef("unsupported operator for strings: %s", op.T) }
func LikeCompare(a, b string) (value.BoolValue, bool) { // Do we want to always do this replacement? Or do this at parse time or config? if strings.Contains(b, "%") { b = strings.Replace(b, "%", "*", -1) } match, err := glob.Match(b, a) //u.Debugf("ran LIKE: match?%v err=%v expr: %s LIKE %s", match, err, b, a) if err != nil { //u.Warnf("invalid like: %q", a) return value.BoolValueFalse, false } if match { return value.BoolValueTrue, true } return value.BoolValueFalse, true }
// FilterFunc Filter out Values that match specified list of match filter criteria // // - Operates on MapValue (map[string]interface{}), StringsValue ([]string), or string // - takes N Filter Criteria // - supports Matching: "filter*" // matches "filter_x", "filterstuff" // // -- Filter a map of values by key to remove certain keys // filter(match("topic_"),key_to_filter, key2_to_filter) => {"goodkey": 22}, true // // -- Filter out VALUES (not keys) from a list of []string{} for a specific value // filter(split("apples,oranges",","),"ora*") => ["apples"], true // // -- Filter out values for single strings // filter("apples","app*") => []string{}, true // func FilterFunc(ctx expr.EvalContext, val value.Value, filterVals ...value.Value) (value.Value, bool) { filters := FiltersFromArgs(filterVals) //u.Debugf("Filter(): %T:%v filters:%v", val, val, filters) switch val := val.(type) { case value.MapValue: mv := make(map[string]interface{}) for rowKey, v := range val.Val() { filteredOut := false for _, filter := range filters { if strings.Contains(filter, "*") { match, _ := glob.Match(filter, rowKey) if match { filteredOut = true break } } else { if strings.HasPrefix(rowKey, filter) && v != nil { filteredOut = true break } } } if !filteredOut { mv[rowKey] = v.Value() } } return value.NewMapValue(mv), true case value.StringValue: anyMatches := false for _, filter := range filters { if strings.Contains(filter, "*") { match, _ := glob.Match(filter, val.Val()) if match { anyMatches = true break } } else { if strings.HasPrefix(val.Val(), filter) { anyMatches = true break } } } if anyMatches { return value.NilValueVal, true } return val, true case value.StringsValue: lv := make([]string, 0, val.Len()) for _, sv := range val.Val() { filteredOut := false for _, filter := range filters { if strings.Contains(filter, "*") { match, _ := glob.Match(filter, sv) if match { filteredOut = true break } } else { if strings.HasPrefix(sv, filter) && sv != "" { filteredOut = true break } } } if !filteredOut { lv = append(lv, sv) } } return value.NewStringsValue(lv), true default: u.Warnf("unsuported key type: %T %v", val, val) } //u.Warnf("could not find key: %T %v", item, item) return nil, false }