From 533e2d6048e6d4748fc04e8316a40c8426401a9e Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 9 Jan 2020 15:52:59 +0200 Subject: [PATCH] Addded NavigableMap.GetKeys() --- config/config_defaults.go | 14 +++---- config/navigablemap.go | 78 ++++++++++++++++++++++++++++++++++++++- engine/filterhelpers.go | 25 ++++++++----- 3 files changed, 100 insertions(+), 17 deletions(-) diff --git a/config/config_defaults.go b/config/config_defaults.go index fdc45234f..0784a17b0 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -534,7 +534,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined "process_runs": 1, // number of run loops when processing event }, @@ -545,7 +545,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined }, @@ -556,7 +556,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined }, @@ -568,7 +568,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined }, @@ -578,7 +578,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined }, @@ -587,7 +587,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined "attributes_conns": [], // connections to AttributeS for altering events before supplier queries: <""|*internal|127.0.0.1:2013> "resources_conns": [], // connections to ResourceS for *res sorting, empty to disable functionality: <""|*internal|x.y.z.y:1234> "stats_conns": [], // connections to StatS for *stats sorting, empty to disable stats functionality: <""|*internal|x.y.z.y:1234> @@ -831,7 +831,7 @@ const CGRATES_CFG_JSON = ` "indexed_selects":true, // enable profile matching exclusively on indexes //"string_indexed_fields": [], // query indexes based on these fields for faster processing "prefix_indexed_fields": [], // query indexes based on these fields for faster processing - "nested_fields":false, // applies when indexed fields is not defined + "nested_fields": false, // applies when indexed fields is not defined "attributes_conns": [], // connections to AttributeS for API authorization, empty to disable auth functionality: <""|*internal|x.y.z.y:1234> }, diff --git a/config/navigablemap.go b/config/navigablemap.go index c06590d3f..091d4bd4f 100644 --- a/config/navigablemap.go +++ b/config/navigablemap.go @@ -309,7 +309,7 @@ func (nM *NavigableMap) Merge(nM2 *NavigableMap) { val, _ := nM2.FieldAsInterface(path) if valItms, isItms := val.([]*NMItem); isItms { pathStr := strings.Join(path, utils.NestingSep) - pathIdx[pathStr] += 1 + pathIdx[pathStr]++ if pathIdx[pathStr] > len(valItms) { val = valItms[len(valItms)-1:] // slice with only last element in, so we can set it unlimited } else { @@ -449,3 +449,79 @@ func (nM *NavigableMap) AsXMLElements() (ents []*XMLElement, err error) { } return } + +func getPathFromValue(in reflect.Value, prefix string) (out []string) { + switch in.Kind() { + case reflect.Ptr: + return getPathFromValue(in.Elem(), prefix) + case reflect.Array, reflect.Slice: + prefix = strings.TrimSuffix(prefix, ".") + for i := 0; i < in.Len(); i++ { + pref := fmt.Sprintf("%s[%v]", prefix, i) + out = append(out, pref) + out = append(out, getPathFromValue(in.Index(i), pref+".")...) + } + case reflect.Map: + iter := reflect.ValueOf(in).MapRange() + for iter.Next() { + pref := prefix + iter.Key().String() + out = append(out, pref) + out = append(out, getPathFromValue(iter.Value(), pref+".")...) + } + case reflect.Struct: + inType := in.Type() + for i := 0; i < in.NumField(); i++ { + pref := prefix + inType.Field(i).Name + out = append(out, pref) + out = append(out, getPathFromValue(in.Field(i), pref+".")...) + } + case reflect.Invalid, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String, reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Interface: + default: + } + return +} + +func getPathFromInterface(in interface{}, prefix string) (out []string) { + switch vin := in.(type) { + case map[string]interface{}: + for k, val := range vin { + pref := prefix + k + out = append(out, pref) + out = append(out, getPathFromInterface(val, pref+".")...) + } + case []map[string]interface{}: + prefix = strings.TrimSuffix(prefix, ".") + for i, val := range vin { + pref := fmt.Sprintf("%s[%v]", prefix, i) + out = append(out, pref) + out = append(out, getPathFromInterface(val, pref+".")...) + } + case []interface{}: + prefix = strings.TrimSuffix(prefix, ".") + for i, val := range vin { + pref := fmt.Sprintf("%s[%v]", prefix, i) + out = append(out, pref) + out = append(out, getPathFromInterface(val, pref+".")...) + } + case []string: + prefix = strings.TrimSuffix(prefix, ".") + for i, val := range vin { + pref := fmt.Sprintf("%s[%v]", prefix, i) + out = append(out, pref) + out = append(out, getPathFromInterface(val, pref+".")...) + } + case nil, int, int32, int64, uint32, uint64, bool, float32, float64, []uint8, time.Duration, time.Time, string: //no path + default: //reflect based + out = getPathFromValue(reflect.ValueOf(vin), prefix) + } + return +} + +// GetKeys returns all posibble keys +func (nM *NavigableMap) GetKeys() (keys []string) { + for k, val := range nM.data { + keys = append(keys, k) + keys = append(keys, getPathFromInterface(val, k+".")...) + } + return +} diff --git a/engine/filterhelpers.go b/engine/filterhelpers.go index 7ab603cf6..4ffbc6f5b 100644 --- a/engine/filterhelpers.go +++ b/engine/filterhelpers.go @@ -32,7 +32,20 @@ import ( func MatchingItemIDsForEvent(ev map[string]interface{}, stringFldIDs, prefixFldIDs *[]string, dm *DataManager, cacheID, itemIDPrefix string, indexedSelects, nestedFields bool) (itemIDs utils.StringMap, err error) { itemIDs = make(utils.StringMap) - + var allFieldIDs []string + navEv := config.NewNavigableMap(ev) + if indexedSelects && (stringFldIDs == nil || prefixFldIDs == nil) { + if !nestedFields { + allFieldIDs = make([]string, len(ev)) + i := 0 + for fldID := range ev { + allFieldIDs[i] = fldID + i++ + } + } else { + allFieldIDs = navEv.GetKeys() + } + } // Guard will protect the function with automatic locking lockID := utils.CacheInstanceToPrefix[cacheID] + itemIDPrefix guardian.Guardian.Guard(func() (gRes interface{}, gErr error) { @@ -48,12 +61,6 @@ func MatchingItemIDsForEvent(ev map[string]interface{}, stringFldIDs, prefixFldI itemIDs = utils.StringMapFromSlice(sliceIDs) return } - allFieldIDs := make([]string, len(ev)) - i := 0 - for fldID := range ev { - allFieldIDs[i] = fldID - i++ - } stringFieldVals := map[string]string{utils.ANY: utils.ANY} // cache here field string values, start with default one filterIndexTypes := []string{utils.MetaString, utils.MetaPrefix, utils.META_NONE} // the META_NONE is used for all items that do not have filters for i, fieldIDs := range []*[]string{stringFldIDs, prefixFldIDs, &[]string{utils.ANY}} { // same routine for both string and prefix filter types @@ -61,8 +68,8 @@ func MatchingItemIDsForEvent(ev map[string]interface{}, stringFldIDs, prefixFldI fieldIDs = &allFieldIDs } for _, fldName := range *fieldIDs { - fieldValIf, has := ev[fldName] - if !has && filterIndexTypes[i] != utils.META_NONE { + fieldValIf, err := navEv.FieldAsInterface(strings.Split(fldName, utils.NestingSep)) + if err != nil && filterIndexTypes[i] != utils.META_NONE { continue } if _, cached := stringFieldVals[fldName]; !cached {