diff --git a/engine/filters_test.go b/engine/filters_test.go index 3da5f9efc..eb8a8d2f4 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -1079,6 +1079,15 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) { } else if !pass { t.Errorf("Expecting: %+v, received: %+v", true, pass) } + + pEv = utils.MapStorage{utils.MetaReq: utils.MapStorage{utils.AccountField: "[1,2,3]"}} + if pass, err := filterS.Pass("cgrates.org", + []string{"*eq:~*req.Account{*slice&*len}:3"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("Expecting: %+v, received: %+v", true, pass) + } + } func TestPassFiltersForEventWithEmptyFilter(t *testing.T) { diff --git a/packages/debian/changelog b/packages/debian/changelog index 79295524d..52637d0a7 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -168,6 +168,7 @@ cgrates (0.11.0~dev) UNRELEASED; urgency=medium * [RSRParsers] Added *len dataconverter * [ERs] Added *nats_json_map * [EEs] Added *nats_json_map + * [RSRParsers] Added *slice dataconverter -- DanB Wed, 19 Feb 2020 13:25:52 +0200 diff --git a/utils/consts.go b/utils/consts.go index b24184b8d..612800079 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -775,6 +775,7 @@ const ( MetaString2Hex = "*string2hex" MetaUnixTime = "*unixtime" MetaLen = "*len" + MetaSlice = "*slice" MetaSIPURIMethod = "*sipuri_method" MetaSIPURIHost = "*sipuri_host" MetaSIPURIUser = "*sipuri_user" diff --git a/utils/dataconverter.go b/utils/dataconverter.go index 2475c072a..874d62925 100644 --- a/utils/dataconverter.go +++ b/utils/dataconverter.go @@ -90,6 +90,8 @@ func NewDataConverter(params string) (conv DataConverter, err error) { return new(UnixTimeConverter), nil case params == MetaLen: return new(LengthConverter), nil + case params == MetaSlice: + return new(SliceConverter), nil case params == MetaFloat64: return new(Float64Converter), nil case strings.HasPrefix(params, MetaLibPhoneNumber): @@ -452,20 +454,91 @@ func (rC *RandomConverter) Convert(in interface{}) ( } } -// LengthConverter converts the interface in the unix time +// LengthConverter returns the lenght of the slice type LengthConverter struct{} // Convert implements DataConverter interface func (LengthConverter) Convert(in interface{}) (out interface{}, err error) { - src := IfaceAsString(in) - if strings.HasPrefix(src, IdxStart) && - strings.HasSuffix(src, IdxEnd) { // it has a similar structure to a json marshaled slice - var slice []interface{} - if err := json.Unmarshal([]byte(src), &slice); err == nil { // no error when unmarshal safe to asume that this is a slice - return len(slice), nil - } + switch val := in.(type) { + case string: + return len(val), nil + case []string: + return len(val), nil + case []interface{}: + return len(val), nil + case []bool: + return len(val), nil + case []int: + return len(val), nil + case []int8: + return len(val), nil + case []int16: + return len(val), nil + case []int32: + return len(val), nil + case []int64: + return len(val), nil + case []uint: + return len(val), nil + case []uint8: + return len(val), nil + case []uint16: + return len(val), nil + case []uint32: + return len(val), nil + case []uint64: + return len(val), nil + case []uintptr: + return len(val), nil + case []float32: + return len(val), nil + case []float64: + return len(val), nil + case []complex64: + return len(val), nil + case []complex128: + return len(val), nil + default: + return len(IfaceAsString(val)), nil + } +} + +// SliceConverter converts the interface in the unix time +type SliceConverter struct{} + +// Convert implements DataConverter interface +func (SliceConverter) Convert(in interface{}) (out interface{}, err error) { + switch val := in.(type) { + case []string, + []interface{}, + []bool, + []int, + []int8, + []int16, + []int32, + []int64, + []uint, + []uint8, + []uint16, + []uint32, + []uint64, + []uintptr, + []float32, + []float64, + []complex64, + []complex128: + return val, nil + default: + src := IfaceAsString(in) + if strings.HasPrefix(src, IdxStart) && + strings.HasSuffix(src, IdxEnd) { // it has a similar structure to a json marshaled slice + var slice []interface{} + if err := json.Unmarshal([]byte(src), &slice); err == nil { // no error when unmarshal safe to asume that this is a slice + return slice, nil + } + } + return src, nil } - return len(src), nil } type Float64Converter struct{} diff --git a/utils/dataconverter_test.go b/utils/dataconverter_test.go index bea5b71a5..0ac9c55ca 100644 --- a/utils/dataconverter_test.go +++ b/utils/dataconverter_test.go @@ -1030,12 +1030,108 @@ func TestLenTimeConverter3(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", exp, cnv) } - expected := 0 + expected := 2 + if rcv, err := cnv.Convert([]int{0, 0}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } if rcv, err := cnv.Convert("[]"); err != nil { t.Error(err) } else if !reflect.DeepEqual(expected, rcv) { t.Errorf("Expecting: %+v, received: %+v", expected, rcv) } + expected = 0 + if rcv, err := cnv.Convert([]string{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]interface{}{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]bool{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]int{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]int8{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]int16{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]int32{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]int64{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uint{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uint8{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uint16{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uint32{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uint64{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]uintptr{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]float32{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]float64{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]complex64{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + if rcv, err := cnv.Convert([]complex128{}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } } func TestFloat64Converter(t *testing.T) { @@ -1062,3 +1158,26 @@ func TestFloat64Converter(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", expected2, err.Error()) } } + +func TestSliceConverter(t *testing.T) { + exp := new(SliceConverter) + cnv, err := NewDataConverter(MetaSlice) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(exp, cnv) { + t.Errorf("Expecting: %+v, received: %+v", exp, cnv) + } + expected := []string{"A", "B"} + if rcv, err := cnv.Convert([]string{"A", "B"}); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } + expected2 := []interface{}{"A", "B"} + if rcv, err := cnv.Convert(`["A","B"]`); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected2, rcv) { + t.Errorf("Expecting: %+v, received: %+v", expected, rcv) + } +}