// Split a string, accepts an optional with parameter // // split(item, ",") // func SplitFunc(ctx expr.EvalContext, input value.Value, splitByV value.StringValue) (value.StringsValue, bool) { sv, ok := value.ToString(input.Rv()) splitBy, splitByOk := value.ToString(splitByV.Rv()) if !ok || !splitByOk { return value.NewStringsValue(make([]string, 0)), false } if sv == "" { return value.NewStringsValue(make([]string, 0)), false } if splitBy == "" { return value.NewStringsValue(make([]string, 0)), false } vals := strings.Split(sv, splitBy) return value.NewStringsValue(vals), true }
func (m ContextUrlValues) Row() map[string]value.Value { mi := make(map[string]value.Value) for k, v := range m.Data { if len(v) == 1 { mi[k] = value.NewValue(v[0]) } else if len(v) > 1 { mi[k] = value.NewStringsValue(v) } } return mi }
// Extract Domains from a Value, or Values (must be urlish), doesn't do much/any validation // // domains("http://www.lytics.io/index.html") => []string{"lytics.io"} // func DomainsFunc(ctx expr.EvalContext, items ...value.Value) (value.StringsValue, bool) { vals := value.NewStringsValue(make([]string, 0)) for _, item := range items { switch itemT := item.(type) { case value.StringValue: vals.Append(itemT.Val()) case value.StringsValue: for _, sv := range itemT.Val() { vals.Append(sv) } } } if vals.Len() == 0 { return vals, true } domains := value.NewStringsValue(make([]string, 0)) for _, val := range vals.Val() { urlstr := strings.ToLower(val) if len(urlstr) < 8 { continue } if !strings.HasPrefix(urlstr, "http") { urlstr = "http://" + urlstr } if urlParsed, err := url.Parse(urlstr); err == nil { parts := strings.Split(urlParsed.Host, ".") if len(parts) > 2 { parts = parts[len(parts)-2:] } if len(parts) > 0 { domains.Append(strings.Join(parts, ".")) } } } return domains, true }
// Extract hosts from a Strings (must be urlish), doesn't do much/any validation // // hosts("http://www.lytics.io", "http://www.activate.lytics.io") => www.lytics.io, www.activate.lytics.io // func HostsFunc(ctx expr.EvalContext, items ...value.Value) (value.StringsValue, bool) { vals := value.NewStringsValue(make([]string, 0)) for _, item := range items { switch itemT := item.(type) { case value.StringValue: vals.Append(itemT.Val()) case value.StringsValue: for _, sv := range itemT.Val() { vals.Append(sv) } case value.SliceValue: for _, sv := range itemT.Val() { vals.Append(sv.ToString()) } } } if vals.Len() == 0 { return vals, true } hosts := value.NewStringsValue(make([]string, 0)) for _, val := range vals.Val() { urlstr := strings.ToLower(val) if len(urlstr) < 8 { continue } if !strings.HasPrefix(urlstr, "http") { urlstr = "http://" + urlstr } if urlParsed, err := url.Parse(urlstr); err == nil { //u.Infof("url.parse: %#v", urlParsed) hosts.Append(urlParsed.Host) } } return hosts, true }
{`gt(toint(price),1)`, value.BoolValueTrue}, {`contains("5tem",5)`, value.BoolValueTrue}, {`contains("5item","item")`, value.BoolValueTrue}, {`contains("the-hello",event)`, value.BoolValueTrue}, {`contains("the-item",event)`, value.BoolValueFalse}, {`contains(price,"$")`, value.BoolValueTrue}, {`contains(url,"membership/all.html")`, value.BoolValueTrue}, {`tolower("Apple")`, value.NewStringValue("apple")}, {`join("apple", event, "oranges", "--")`, value.NewStringValue("apple--hello--oranges")}, {`join(["apple","peach"], ",")`, value.NewStringValue("apple,peach")}, {`join("apple","","peach",",")`, value.NewStringValue("apple,peach")}, {`split("apples,oranges",",")`, value.NewStringsValue([]string{"apples", "oranges"})}, {`replace("M20:30","M")`, value.NewStringValue("20:30")}, {`replace("/search/for+stuff","/search/")`, value.NewStringValue("for+stuff")}, {`oneof("apples","oranges")`, value.NewStringValue("apples")}, {`oneof(notincontext,event)`, value.NewStringValue("hello")}, {`any(5)`, value.BoolValueTrue}, // TODO: {`any(0)`, value.BoolValueFalse}, {`any("value")`, value.BoolValueTrue}, {`any(event)`, value.BoolValueTrue}, {`any(notrealfield)`, value.BoolValueFalse}, {`all("Apple")`, value.BoolValueTrue}, {`all("Apple")`, value.BoolValueTrue},
{`tolower("Apple")`, value.NewStringValue("apple")}, {`len(["5","6"])`, value.NewIntValue(2)}, {`len("abc")`, value.NewIntValue(3)}, {`len(split(reg_date,"/"))`, value.NewIntValue(3)}, {`len(not_a_field)`, nil}, {`len(not_a_field) >= 10`, value.BoolValueFalse}, {`len("abc") >= 2`, value.BoolValueTrue}, {`CHAR_LENGTH("abc") `, value.NewIntValue(3)}, {`CHAR_LENGTH(CAST("abc" AS CHAR))`, value.NewIntValue(3)}, {`join("apple", event, "oranges", "--")`, value.NewStringValue("apple--hello--oranges")}, {`join(["apple","peach"], ",")`, value.NewStringValue("apple,peach")}, {`join("apple","","peach",",")`, value.NewStringValue("apple,peach")}, {`split("apples,oranges",",")`, value.NewStringsValue([]string{"apples", "oranges"})}, {`replace("M20:30","M")`, value.NewStringValue("20:30")}, {`replace("/search/for+stuff","/search/")`, value.NewStringValue("for+stuff")}, {`replace("M20:30","M","")`, value.NewStringValue("20:30")}, {`replace("M20:30","M","Hour ")`, value.NewStringValue("Hour 20:30")}, {`oneof("apples","oranges")`, value.NewStringValue("apples")}, {`oneof(notincontext,event)`, value.NewStringValue("hello")}, {`any(5)`, value.BoolValueTrue}, // TODO: {`any(0)`, value.BoolValueFalse}, {`any("value")`, value.BoolValueTrue}, {`any(event)`, value.BoolValueTrue}, {`any(notrealfield)`, value.BoolValueFalse},
builtins.LoadAllBuiltins() } var ( t1, _ = dateparse.ParseAny("12/18/2019") // This is the message context which will be added to all tests below // and be available to the VM runtime for evaluation by using // key's such as "int5" or "user_id" msgContext = datasource.NewContextSimpleData(map[string]value.Value{ "int5": value.NewIntValue(5), "str5": value.NewStringValue("5"), "created": value.NewTimeValue(t1), "bvalt": value.NewBoolValue(true), "bvalf": value.NewBoolValue(false), "user_id": value.NewStringValue("abc"), "urls": value.NewStringsValue([]string{"abc", "123"}), "hits": value.NewMapIntValue(map[string]int64{"google.com": 5, "bing.com": 1}), "email": value.NewStringValue("*****@*****.**"), }) vmTestsx = []vmTest{ // Native LIKE keyword vmt(`["portland"] LIKE "*land"`, true, noError), } // list of tests vmTests = []vmTest{ // Date math vmt(`created > "now-1M"`, true, noError), vmt(`now() > todate("01/01/2014")`, true, noError), vmt(`todate("now+3d") > now()`, true, noError), vmt(`created < 2032220220175`, true, noError), // Really not sure i want to support this?
// 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 }