コード例 #1
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// Convert to Integer:   Best attempt at converting to integer
//
//   toint("5") => 5
//   toint("5.75") => 5
//   toint("5,555") => 5555
//   toint("$5") => 5
//   toint("5,555.00") => 5555
//
func ToInt(ctx expr.EvalContext, item value.Value) (value.IntValue, bool) {
	iv, ok := value.ToInt64(reflect.ValueOf(item.Value()))
	if !ok {
		return value.NewIntValue(0), false
	}
	return value.NewIntValue(iv), true
}
コード例 #2
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
//  Not:   urnary negation function
//
//      eq(item,5)
func NotFunc(ctx expr.EvalContext, item value.Value) (value.BoolValue, bool) {
	boolVal, ok := value.ToBool(item.Rv())
	if ok {
		return value.NewBoolValue(!boolVal), true
	}
	return value.BoolValueFalse, false
}
コード例 #3
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// Convert to Number:   Best attempt at converting to integer
//
//   tonumber("5") => 5.0
//   tonumber("5.75") => 5.75
//   tonumber("5,555") => 5555
//   tonumber("$5") => 5.00
//   tonumber("5,555.00") => 5555
//
func ToNumber(ctx expr.EvalContext, item value.Value) (value.NumberValue, bool) {
	fv, ok := value.ToFloat64(reflect.ValueOf(item.Value()))
	if !ok {
		return value.NewNumberValue(0), false
	}
	return value.NewNumberValue(fv), true
}
コード例 #4
0
ファイル: builtins.go プロジェクト: jmptrader/qlbridge
// Extract host from a String (must be urlish), doesn't do much/any validation
func Qs(ctx expr.EvalContext, urlItem, keyItem value.Value) (value.StringValue, bool) {
	val, ok := value.ToString(urlItem.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if val == "" {
		return value.EmptyStringValue, false
	}
	urlstr := strings.ToLower(val)
	if len(urlstr) < 8 {
		return value.EmptyStringValue, false
	}
	keyVal, ok := value.ToString(keyItem.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if keyVal == "" {
		return value.EmptyStringValue, false
	}
	if !strings.HasPrefix(urlstr, "http") {
		urlstr = "http://" + urlstr
	}
	if urlParsed, err := url.Parse(urlstr); err == nil {
		//u.Infof("url.parse: %#v", urlParsed)
		qsval, ok := urlParsed.Query()[keyVal]
		if !ok {
			return value.EmptyStringValue, false
		}
		if len(qsval) > 0 {
			return value.NewStringValue(qsval[0]), true
		}
	}

	return value.EmptyStringValue, false
}
コード例 #5
0
ファイル: nativefuncs.go プロジェクト: kyledj/qlbridge
// Count
func CountFunc(ctx EvalContext, val value.Value) (value.IntValue, bool) {
	if val.Err() || val.Nil() {
		return value.NewIntValue(0), false
	}
	//u.Infof("???   vals=[%v]", val.Value())
	return value.NewIntValue(1), true
}
コード例 #6
0
ファイル: vm_test.go プロジェクト: schmichael/qlbridge
//  Equal function?  returns true if items are equal
//
//      eq(item,5)
func Eq(ctx expr.EvalContext, itemA, itemB value.Value) (value.BoolValue, bool) {
	//return BoolValue(itemA == itemB)
	//rvb := value.CoerceTo(itemA.Rv(), itemB.Rv())
	//u.Infof("Eq():    a:%T  b:%T     %v=%v?", itemA, itemB, itemA.Value(), rvb)
	//u.Infof("Eq()2:  %T %T", itemA.Rv(), rvb)
	return value.NewBoolValue(reflect.DeepEqual(itemA.Value(), itemB.Value())), true
}
コード例 #7
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// String lower function
//   must be able to convert to string
//
func Lower(ctx expr.EvalContext, item value.Value) (value.StringValue, bool) {
	val, ok := value.ToString(item.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	return value.NewStringValue(strings.ToLower(val)), true
}
コード例 #8
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// <= Less Than or Equal
//  Must be able to convert items to Floats or else not ok
//
func LeFunc(ctx expr.EvalContext, lv, rv value.Value) (value.BoolValue, bool) {
	left, _ := value.ToFloat64(lv.Rv())
	right, _ := value.ToFloat64(rv.Rv())
	if math.IsNaN(left) || math.IsNaN(right) {
		return value.BoolValueFalse, false
	}
	return value.NewBoolValue(left <= right), true
}
コード例 #9
0
ファイル: builtins.go プロジェクト: jmptrader/qlbridge
// < Less Than
//  Must be able to convert items to Floats or else not ok
//
func LtFunc(ctx expr.EvalContext, lv, rv value.Value) (value.BoolValue, bool) {
	left := value.ToFloat64(lv.Rv())
	right := value.ToFloat64(rv.Rv())
	if left == math.NaN() || right == math.NaN() {
		return value.BoolValueFalse, false
	}

	return value.NewBoolValue(left < right), true
}
コード例 #10
0
ファイル: main.go プロジェクト: kyledj/qlbridge
// Example of a custom Function, that we are adding into the Expression VM
//
//         select
//              user_id AS theuserid, email, item_count * 2, reg_date
//         FROM stdio
//         WHERE email_is_valid(email)
func EmailIsValid(ctx expr.EvalContext, email value.Value) (value.BoolValue, bool) {
	emailstr, ok := value.ToString(email.Rv())
	if !ok || emailstr == "" {
		return value.BoolValueFalse, true
	}
	if _, err := mail.ParseAddress(emailstr); err == nil {
		return value.BoolValueTrue, true
	}

	return value.BoolValueFalse, true
}
コード例 #11
0
ファイル: builtins.go プロジェクト: jmptrader/qlbridge
// todate
func ToDate(ctx expr.EvalContext, item value.Value) (value.TimeValue, bool) {

	dateStr, ok := value.ToString(item.Rv())
	if !ok {
		return value.TimeZeroValue, false
	}
	//u.Infof("v=%v   %v  ", v, item.Rv())
	if t, err := dateparse.ParseAny(dateStr); err == nil {
		return value.NewTimeValue(t), true
	}

	return value.TimeZeroValue, false
}
コード例 #12
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// Sqrt
//
//      sqrt(4)            =>  2, true
//      sqrt(9)            =>  3, true
//      sqrt(not_number)   =>  0, false
//
func SqrtFunc(ctx expr.EvalContext, val value.Value) (value.NumberValue, bool) {
	nv, ok := val.(value.NumericValue)
	if !ok {
		return value.NewNumberValue(math.NaN()), false
	}
	if val.Err() || val.Nil() {
		return value.NewNumberValue(0), false
	}
	fv := nv.Float()
	fv = math.Sqrt(fv)
	//u.Infof("???   vals=[%v]", val.Value())
	return value.NewNumberValue(fv), true
}
コード例 #13
0
ファイル: builtins.go プロジェクト: allisonmorgan/qlbridge
// Convert to Integer:   Best attempt at converting to integer
//
//   toint("5")          => 5, true
//   toint("5.75")       => 5, true
//   toint("5,555")      => 5555, true
//   toint("$5")         => 5, true
//   toint("5,555.00")   => 5555, true
//
func ToInt(ctx expr.EvalContext, item value.Value) (value.IntValue, bool) {

	switch itemT := item.(type) {
	case value.TimeValue:
		iv := itemT.Val().UnixNano() / 1e6 // Milliseconds
		return value.NewIntValue(iv), true
	}
	iv, ok := value.ToInt64(reflect.ValueOf(item.Value()))
	if !ok {
		return value.NewIntValue(0), false
	}
	return value.NewIntValue(iv), true
}
コード例 #14
0
ファイル: builtins.go プロジェクト: allisonmorgan/qlbridge
// totimestamp:   convert to date, then to unix Seconds
//
func ToTimestamp(ctx expr.EvalContext, item value.Value) (value.IntValue, bool) {

	dateStr, ok := value.ToString(item.Rv())
	if !ok {
		return value.NewIntValue(0), false
	}
	if t, err := dateparse.ParseAny(dateStr); err == nil {
		//u.Infof("v=%v   %v  unix=%v", item, item.Rv(), t.Unix())
		return value.NewIntValue(int64(t.Unix())), true
	}

	return value.NewIntValue(0), false
}
コード例 #15
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// String contains
//   Will first convert to string, so may get unexpected results
//
func ContainsFunc(ctx expr.EvalContext, lv, rv value.Value) (value.BoolValue, bool) {
	left, leftOk := value.ToString(lv.Rv())
	right, rightOk := value.ToString(rv.Rv())
	if !leftOk || !rightOk {
		return value.BoolValueFalse, false
	}
	//u.Infof("Contains(%v, %v)", left, right)
	if left == "" || right == "" {
		return value.BoolValueFalse, false
	}
	if strings.Contains(left, right) {
		return value.BoolValueTrue, true
	}
	return value.BoolValueFalse, true
}
コード例 #16
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// 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
}
コード例 #17
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// emailname a string, parses email
//
//     emailname("Bob <*****@*****.**>") =>  Bob
//
func EmailNameFunc(ctx expr.EvalContext, item value.Value) (value.StringValue, bool) {
	val, ok := value.ToString(item.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if val == "" {
		return value.EmptyStringValue, false
	}
	if len(val) < 6 {
		return value.EmptyStringValue, false
	}

	if em, err := mail.ParseAddress(val); err == nil {
		return value.NewStringValue(em.Name), true
	}

	return value.EmptyStringValue, false
}
コード例 #18
0
ファイル: vm_test.go プロジェクト: schmichael/qlbridge
func Yy(ctx expr.EvalContext, item value.Value) (value.IntValue, bool) {

	//u.Info("yy:   %T", item)
	val, ok := value.ToString(item.Rv())
	if !ok || val == "" {
		return value.NewIntValue(0), false
	}
	//u.Infof("v=%v   %v  ", val, item.Rv())
	if t, err := dateparse.ParseAny(val); err == nil {
		yy := t.Year()
		if yy >= 2000 {
			yy = yy - 2000
		} else if yy >= 1900 {
			yy = yy - 1900
		}
		//u.Infof("Yy = %v   yy = %v", item, yy)
		return value.NewIntValue(int64(yy)), true
	}

	return value.NewIntValue(0), false
}
コード例 #19
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// email a string, parses email
//
//     email("Bob <*****@*****.**>") =>  [email protected]
//
func EmailDomainFunc(ctx expr.EvalContext, item value.Value) (value.StringValue, bool) {
	val, ok := value.ToString(item.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if val == "" {
		return value.EmptyStringValue, false
	}
	if len(val) < 6 {
		return value.EmptyStringValue, false
	}

	if em, err := mail.ParseAddress(strings.ToLower(val)); err == nil {
		parts := strings.SplitN(strings.ToLower(em.Address), "@", 2)
		if len(parts) == 2 {
			return value.NewStringValue(parts[1]), true
		}
	}

	return value.EmptyStringValue, false
}
コード例 #20
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// urlminusqs removes a specific query parameter and its value from a url
//
//     urlminusqs("http://www.lytics.io/?q1=google&q2=123", "q1") => "http://www.lytics.io/?q2=123", true
//
func UrlMinusQs(ctx expr.EvalContext, urlItem, keyItem value.Value) (value.StringValue, bool) {
	val := ""
	switch itemT := urlItem.(type) {
	case value.StringValue:
		val = itemT.Val()
	case value.StringsValue:
		if len(itemT.Val()) == 0 {
			return value.EmptyStringValue, false
		}
		val = itemT.Val()[0]
	}
	if val == "" {
		return value.EmptyStringValue, false
	}
	if !strings.HasPrefix(val, "http") {
		val = "http://" + val
	}
	keyVal, ok := value.ToString(keyItem.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if keyVal == "" {
		return value.EmptyStringValue, false
	}
	if up, err := url.Parse(val); err == nil {
		qsval := up.Query()
		_, ok := qsval[keyVal]
		if !ok {
			return value.NewStringValue(fmt.Sprintf("%s://%s%s?%s", up.Scheme, up.Host, up.Path, up.RawQuery)), true
		}
		qsval.Del(keyVal)
		up.RawQuery = qsval.Encode()
		if up.RawQuery == "" {
			return value.NewStringValue(fmt.Sprintf("%s://%s%s", up.Scheme, up.Host, up.Path)), true
		}
		return value.NewStringValue(fmt.Sprintf("%s://%s%s?%s", up.Scheme, up.Host, up.Path, up.RawQuery)), true
	}

	return value.EmptyStringValue, false
}
コード例 #21
0
ファイル: builtins.go プロジェクト: jmptrader/qlbridge
// Extract url path from a String (must be urlish), doesn't do much/any validation
func UrlPath(ctx expr.EvalContext, item value.Value) (value.StringValue, bool) {
	val, ok := value.ToString(item.Rv())
	if !ok {
		return value.EmptyStringValue, false
	}
	if val == "" {
		return value.EmptyStringValue, false
	}
	urlstr := strings.ToLower(val)
	if len(urlstr) < 8 {
		return value.EmptyStringValue, false
	}
	if !strings.HasPrefix(urlstr, "http") {
		urlstr = "http://" + urlstr
	}
	if urlParsed, err := url.Parse(urlstr); err == nil {
		//u.Infof("url.parse: %#v", urlParsed)
		return value.NewStringValue(urlParsed.Path), true
	}

	return value.EmptyStringValue, false
}
コード例 #22
0
ファイル: builtins.go プロジェクト: allisonmorgan/qlbridge
// HashSha512Func Hash a value to SHA512 string
//
//     hash.sha512("/blog/index.html")  =>  abc345xyz
//
func HashSha512Func(ctx expr.EvalContext, arg value.Value) (value.StringValue, bool) {
	if arg.Err() || arg.Nil() {
		return value.EmptyStringValue, true
	}
	hasher := sha512.New()
	hasher.Write([]byte(arg.ToString()))
	return value.NewStringValue(hex.EncodeToString(hasher.Sum(nil))), true
}
コード例 #23
0
func checkval(t *testing.T, r expr.ContextReader, key string, expected value.Value) {
	val, ok := r.Get(key)
	assert.Tf(t, ok, "expected key:%s =%v", key, expected.Value())
	if val == nil {
		t.Errorf("not value for %v", key)
	} else {
		assert.Equalf(t, expected.Value(), val.Value(), "%s expected: %v  got:%v", key, expected.Value(), val.Value())
	}
}
コード例 #24
0
ファイル: builtins.go プロジェクト: allisonmorgan/qlbridge
// Count:   This should be renamed Increment
//      and in general is a horrible, horrible function that needs to be replaced
//      with occurences of value, ignores the value and ensures it is non null
//
//      count(anyvalue)     =>  1, true
//      count(not_number)   =>  -- 0, false
//
func CountFunc(ctx expr.EvalContext, val value.Value) (value.IntValue, bool) {
	if val.Err() || val.Nil() {
		return value.NewIntValue(0), false
	}
	return value.NewIntValue(1), true
}
コード例 #25
0
ファイル: vm_test.go プロジェクト: schmichael/qlbridge
func ToInt(ctx expr.EvalContext, item value.Value) (value.IntValue, bool) {
	iv, _ := value.ToInt64(reflect.ValueOf(item.Value()))
	return value.NewIntValue(iv), true
	//return IntValue(2)
}
コード例 #26
0
ファイル: builtins.go プロジェクト: allisonmorgan/qlbridge
// 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
}
コード例 #27
0
ファイル: nativefuncs.go プロジェクト: kyledj/qlbridge
// Pow
func PowFunc(ctx EvalContext, val, toPower value.Value) (value.NumberValue, bool) {
	//Pow(x, y float64) float64
	//u.Infof("powFunc:  %T:%v %T:%v ", val, val.Value(), toPower, toPower.Value())
	if val.Err() || val.Nil() {
		return value.NewNumberValue(0), false
	}
	if toPower.Err() || toPower.Nil() {
		return value.NewNumberValue(0), false
	}
	fv, _ := value.ToFloat64(val.Rv())
	pow, _ := value.ToFloat64(toPower.Rv())
	if math.IsNaN(fv) || math.IsNaN(pow) {
		return value.NewNumberValue(0), false
	}
	fv = math.Pow(fv, pow)
	//u.Infof("pow ???   vals=[%v]", fv, pow)
	return value.NewNumberValue(fv), true
}
コード例 #28
0
ファイル: parse_test.go プロジェクト: chrislusf/qlbridge
//  Equal function?  returns true if items are equal
//
//      eq(item,5)
func Eq(e *State, itemA, itemB value.Value) (value.BoolValue, bool) {
	//return BoolValue(itemA == itemB)
	rvb := value.CoerceTo(itemA.Rv(), itemB.Rv())
	//u.Infof("Eq():    a:%T  b:%T     %v=%v?", itemA, itemB, itemA.Value(), rvb)
	return value.NewBoolValue(reflect.DeepEqual(itemA.Rv(), rvb)), true
}
コード例 #29
0
ファイル: parse_test.go プロジェクト: chrislusf/qlbridge
func ToInt(e *State, item value.Value) (value.IntValue, bool) {
	iv, _ := value.ToInt64(reflect.ValueOf(item.Value()))
	return value.NewIntValue(iv), true
	//return IntValue(2)
}
コード例 #30
0
ファイル: builtins.go プロジェクト: kyledj/qlbridge
// Map()    Create a map from two values.   If the right side value is nil
//    then does not evaluate
//
//  Map(left, right)    => map[string]value{left:right}
//
func MapFunc(ctx expr.EvalContext, lv, rv value.Value) (value.MapValue, bool) {
	if lv.Err() || rv.Err() {
		return value.EmptyMapValue, false
	}
	if lv.Nil() || rv.Nil() {
		return value.EmptyMapValue, false
	}
	return value.NewMapValue(map[string]interface{}{lv.ToString(): rv.Value()}), true
}