// Get year in integer from field, must be able to convert to date // // yy() => 15, true // assuming it is 2015 // yy("2014-03-01") => 14, true // func Yy(ctx expr.EvalContext, items ...value.Value) (value.IntValue, bool) { yy := 0 if len(items) == 0 { if !ctx.Ts().IsZero() { yy = ctx.Ts().Year() } else { // Do we want to use Now()? } } else if len(items) == 1 { //u.Debugf("has 1 items? %#v", items[0].Rv()) dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.NewIntValue(0), false } //u.Debugf("v=%v %v", dateStr, items[0].Rv()) if t, err := dateparse.ParseAny(dateStr); err != nil { return value.NewIntValue(0), false } else { yy = t.Year() } } else { return value.NewIntValue(0), false } if yy >= 2000 { yy = yy - 2000 } else if yy >= 1900 { yy = yy - 1900 } //u.Debugf("yy = %v", yy) return value.NewIntValue(int64(yy)), true }
// Get year in integer from date func Yy(ctx expr.EvalContext, items ...value.Value) (value.IntValue, bool) { yy := 0 if len(items) == 0 { if !ctx.Ts().IsZero() { yy = ctx.Ts().Year() } } else if len(items) == 1 { dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.NewIntValue(0), false } //u.Infof("v=%v %v ", v, item.Rv()) if t, err := dateparse.ParseAny(dateStr); err != nil { return value.NewIntValue(0), false } else { yy = t.Year() } } else { return value.NewIntValue(0), false } if yy >= 2000 { yy = yy - 2000 } else if yy >= 1900 { yy = yy - 1900 } //u.Infof("%v yy = %v", item, yy) return value.NewIntValue(int64(yy)), true }
// match: Match a simple pattern match and return matched value // // given input: // {"score_value":24,"event_click":true} // // match("score_") => {"value":24} // match("amount_") => false // match("event_") => {"click":true} // func Match(ctx expr.EvalContext, items ...value.Value) (value.MapValue, bool) { //u.Debugf("Match(): %T %v", item, item) mv := make(map[string]interface{}) for _, item := range items { switch node := item.(type) { case value.StringValue: matchKey := node.Val() for rowKey, val := range ctx.Row() { if strings.HasPrefix(rowKey, matchKey) && val != nil { newKey := strings.Replace(rowKey, matchKey, "", 1) if newKey != "" { mv[newKey] = val } } } default: u.Warnf("unsuported key type: %T %v", item, item) } } if len(mv) > 0 { //u.Infof("found new: %v", mv) return value.NewMapValue(mv), true } //u.Warnf("could not find key: %T %v", item, item) return value.EmptyMapValue, false }
// Get current time of Message (message time stamp) or else choose current // server time if none is available in message context // func Now(ctx expr.EvalContext, items ...value.Value) (value.TimeValue, bool) { if ctx != nil && !ctx.Ts().IsZero() { t := ctx.Ts() return value.NewTimeValue(t), true } return value.NewTimeValue(time.Now().In(time.UTC)), true }
func walkIdentity(ctx expr.EvalContext, node *expr.IdentityNode) (value.Value, bool) { if node.IsBooleanIdentity() { //u.Debugf("walkIdentity() boolean: node=%T %v Bool:%v", node, node, node.Bool()) return value.NewBoolValue(node.Bool()), true } if ctx == nil { return value.NewStringValue(node.Text), true } return ctx.Get(node.Text) }
func TimeExtractFunc(ctx expr.EvalContext, items ...value.Value) (value.StringValue, bool) { switch len(items) { case 0: // if we have no "items", return time associated with ctx // This is an alias of now() t := ctx.Ts() if !t.IsZero() { return value.NewStringValue(t.String()), true } return value.EmptyStringValue, false case 1: // if only 1 item, convert item to time dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.EmptyStringValue, false } t, err := dateparse.ParseAny(dateStr) if err != nil { return value.EmptyStringValue, false } return value.NewStringValue(t.String()), true case 2: // if we have 2 items, the first is the time string // and the second is the format string. // Use leekchan/timeutil package dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.EmptyStringValue, false } formatStr, ok := value.ToString(items[1].Rv()) if !ok { return value.EmptyStringValue, false } t, err := dateparse.ParseAny(dateStr) if err != nil { return value.EmptyStringValue, false } formatted := timeutil.Strftime(&t, formatStr) return value.NewStringValue(formatted), true default: return value.EmptyStringValue, false } }
// hour of day [0-23] func HourOfDay(ctx expr.EvalContext, items ...value.Value) (value.IntValue, bool) { if len(items) == 0 { if !ctx.Ts().IsZero() { return value.NewIntValue(int64(ctx.Ts().Hour())), true } } else if len(items) == 1 { dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.NewIntValue(0), false } //u.Infof("v=%v %v ", v, items[0].Rv()) if t, err := dateparse.ParseAny(dateStr); err == nil { return value.NewIntValue(int64(t.Hour())), true } } return value.NewIntValue(0), false }
// Exists func Exists(ctx expr.EvalContext, item interface{}) (value.BoolValue, bool) { //u.Debugf("Exists(): %T %v", item, item) switch node := item.(type) { case expr.IdentityNode: _, ok := ctx.Get(node.Text) if ok { return value.BoolValueTrue, true } return value.BoolValueFalse, true case expr.StringNode: _, ok := ctx.Get(node.Text) if ok { return value.BoolValueTrue, true } return value.BoolValueFalse, true } return value.BoolValueFalse, true }
// Exists: Answers True/False if the field exists and is non null // // exists(real_field) => true // exists("value") => true // exists("") => false // exists(empty_field) => false // exists(2) => true // exists(todate(date_field)) => true // func Exists(ctx expr.EvalContext, item interface{}) (value.BoolValue, bool) { //u.Debugf("Exists(): %T %v", item, item) switch node := item.(type) { case expr.IdentityNode: _, ok := ctx.Get(node.Text) if ok { return value.BoolValueTrue, true } return value.BoolValueFalse, true case expr.StringNode: _, ok := ctx.Get(node.Text) if ok { return value.BoolValueTrue, true } return value.BoolValueFalse, true case value.StringValue: if node.Nil() { return value.BoolValueFalse, true } return value.BoolValueTrue, true case value.BoolValue: return value.BoolValueTrue, true case value.NumberValue: if node.Nil() { return value.BoolValueFalse, true } return value.BoolValueTrue, true case value.IntValue: if node.Nil() { return value.BoolValueFalse, true } return value.BoolValueTrue, true case value.TimeValue: if node.Nil() { return value.BoolValueFalse, true } return value.BoolValueTrue, true case value.StringsValue, value.SliceValue, value.MapIntValue: return value.BoolValueTrue, true } return value.BoolValueFalse, true }
// Get yymm in 4 digits from argument if supplied, else uses message context ts // func YyMm(ctx expr.EvalContext, items ...value.Value) (value.StringValue, bool) { if len(items) == 0 { if !ctx.Ts().IsZero() { t := ctx.Ts() return value.NewStringValue(t.Format(yymmTimeLayout)), true } } else if len(items) == 1 { dateStr, ok := value.ToString(items[0].Rv()) if !ok { return value.EmptyStringValue, false } //u.Infof("v=%v %v ", v, items[0].Rv()) if t, err := dateparse.ParseAny(dateStr); err == nil { return value.NewStringValue(t.Format(yymmTimeLayout)), true } } return value.EmptyStringValue, false }
// Get current time of Message (message time stamp) or else choose current // server time if none is available in message context // func Now(ctx expr.EvalContext, items ...value.Value) (value.TimeValue, bool) { u.Debugf("Now: %v", ctx.Ts()) if !ctx.Ts().IsZero() { t := ctx.Ts() return value.NewTimeValue(t), true } return value.NewTimeValue(time.Now().In(time.UTC)), true }
func walkFunc(ctx expr.EvalContext, node *expr.FuncNode) (value.Value, bool) { //u.Debugf("walkFunc node: %v", node.StringAST()) // we create a set of arguments to pass to the function, first arg // is this Context var ok bool funcArgs := make([]reflect.Value, 0) if ctx != nil { funcArgs = append(funcArgs, reflect.ValueOf(ctx)) } else { var nilArg expr.EvalContext funcArgs = append(funcArgs, reflect.ValueOf(&nilArg).Elem()) } for _, a := range node.Args { //u.Debugf("arg %v %T %v", a, a, a) var v interface{} switch t := a.(type) { case *expr.StringNode: // String Literal v = value.NewStringValue(t.Text) case *expr.IdentityNode: // Identity node = lookup in context if t.IsBooleanIdentity() { v = value.NewBoolValue(t.Bool()) } else { v, ok = ctx.Get(t.Text) //u.Infof("%#v", ctx.Row()) //u.Debugf("get '%s'? %T %v %v", t.String(), v, v, ok) if !ok { // nil arguments are valid v = value.NewNilValue() } } case *expr.NumberNode: v, ok = numberNodeToValue(t) case *expr.FuncNode: //u.Debugf("descending to %v()", t.Name) v, ok = walkFunc(ctx, t) if !ok { //return value.NewNilValue(), false // nil arguments are valid v = value.NewNilValue() } //u.Debugf("result of %v() = %v, %T", t.Name, v, v) case *expr.UnaryNode: v, ok = walkUnary(ctx, t) if !ok { // nil arguments are valid ?? v = value.NewNilValue() } case *expr.BinaryNode: v, ok = walkBinary(ctx, t) case *expr.ValueNode: v = t.Value default: panic(fmt.Errorf("expr: unknown func arg type")) } if v == nil { //u.Warnf("Nil vals? %v %T arg:%T", v, v, a) // What do we do with Nil Values? switch a.(type) { case *expr.StringNode: // String Literal u.Warnf("NOT IMPLEMENTED T:%T v:%v", a, a) case *expr.IdentityNode: // Identity node = lookup in context v = value.NewStringValue("") default: u.Warnf("un-handled type: %v %T", v, v) } funcArgs = append(funcArgs, reflect.ValueOf(v)) } else { //u.Debugf(`found func arg: "%v" %T arg:%T`, v, v, a) funcArgs = append(funcArgs, reflect.ValueOf(v)) } } // Get the result of calling our Function (Value,bool) //u.Debugf("Calling func:%v(%v) %v", node.F.Name, funcArgs, node.F.F) fnRet := node.F.F.Call(funcArgs) //u.Debugf("fnRet: %v ok?%v", fnRet, fnRet[1].Bool()) // check if has an error response? if len(fnRet) > 1 && !fnRet[1].Bool() { // What do we do if not ok? return value.EmptyStringValue, false } //u.Debugf("response %v %v %T", node.F.Name, fnRet[0].Interface(), fnRet[0].Interface()) return fnRet[0].Interface().(value.Value), true }