diff --git a/engine/librankings.go b/engine/librankings.go
index ddb640d51..c87ea2d23 100644
--- a/engine/librankings.go
+++ b/engine/librankings.go
@@ -19,6 +19,7 @@ along with this program. If not, see
package engine
import (
+ "sort"
"sync"
"github.com/cgrates/cgrates/utils"
@@ -102,7 +103,8 @@ type rankingSorter interface {
}
// rankingSortStats will return the list of sorted statIDs out of the sortingData map
-func rankingSortStats(sortingType string, sortingParams []string, statMetrics map[string]map[string]float64) (sortedStatIDs []string, err error) {
+func rankingSortStats(sortingType string, sortingParams []string,
+ statMetrics map[string]map[string]float64) (sortedStatIDs []string, err error) {
var rnkSrtr rankingSorter
if rnkSrtr, err = newRankingSorter(sortingType, sortingParams, statMetrics); err != nil {
return
@@ -119,18 +121,59 @@ func newRankingSorter(sortingType string, sortingParams []string,
default:
err = utils.ErrPrefixNotErrNotImplemented(sortingType)
return
- case utils.MetaDescending:
- return &rankingDescSorter{sortingParams, statMetrics}, nil
-
+ case utils.MetaDesc:
+ return newRankingDescSorter(sortingParams, statMetrics), nil
}
+ return
+}
+
+// newRankingDescSorter is a constructor for rankingDescSorter
+func newRankingDescSorter(sortingParams []string,
+ statMetrics map[string]map[string]float64) (rkDsrtr *rankingDescSorter) {
+ rkDsrtr = &rankingDescSorter{
+ sortingParams,
+ statMetrics,
+ make([]string, 0, len(statMetrics))}
+ for statID := range rkDsrtr.statMetrics {
+ rkDsrtr.statIDs = append(rkDsrtr.statIDs, statID)
+ }
+ return
}
// rankingDescSorter will sort data descendently for metrics in sortingParams or randomly if all equal
type rankingDescSorter struct {
sortingParams []string
statMetrics map[string]map[string]float64
+
+ statIDs []string // list of keys of the statMetrics
}
-func (rkDsrtr *rankingDescSorter) sortStatIDs() (statIDs []string) {
- return
+// sortStatIDs implements rankingSorter interface
+func (rkDsrtr *rankingDescSorter) sortStatIDs() []string {
+ if len(rkDsrtr.statIDs) == 0 {
+ return rkDsrtr.statIDs
+ }
+ sort.Slice(rkDsrtr.statIDs, func(i, j int) bool {
+ for _, metricID := range rkDsrtr.sortingParams {
+ val1, hasMetric1 := rkDsrtr.statMetrics[rkDsrtr.statIDs[i]][metricID]
+ if !hasMetric1 {
+ return false
+ }
+ val2, hasMetric2 := rkDsrtr.statMetrics[rkDsrtr.statIDs[j]][metricID]
+ if !hasMetric2 {
+ return true
+ }
+ //in case we have the same value for the current metricID we skip to the next one
+ if val1 == val2 {
+ continue
+ }
+ if val1 > val2 {
+ return true
+ }
+ return false
+ }
+ //in case that we have the same value for all params we return randomly
+ return utils.BoolGenerator().RandomBool()
+ })
+ return rkDsrtr.statIDs
}
diff --git a/engine/librankings_test.go b/engine/librankings_test.go
new file mode 100644
index 000000000..3102cd963
--- /dev/null
+++ b/engine/librankings_test.go
@@ -0,0 +1,44 @@
+/*
+Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
+Copyright (C) ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package engine
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestRankingDescSorterSortStatIDs(t *testing.T) {
+ statMetrics := map[string]map[string]float64{
+ "STATS1": {"*acc": 12.1, "*tcc": 24.2},
+ "STATS2": {"*acc": 12.1, "*tcc": 24.3},
+ "STATS3": {"*acc": 10.1, "*tcc": 25.3},
+ }
+ sortMetrics := []string{"*acc", "*tcc"}
+ rdscSrtr := newRankingDescSorter(sortMetrics,statMetrics)
+ eStatIDs := []string{"STATS2", "STATS1", "STATS3"}
+ if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) {
+ t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs)
+ }
+ sortMetrics = []string{"*tcc", "*acc"} // changed the order of checks, stats3 should come first
+ rdscSrtr = newRankingDescSorter(sortMetrics,statMetrics)
+ eStatIDs = []string{"STATS3", "STATS2", "STATS1"}
+ if statIDs := rdscSrtr.sortStatIDs(); !reflect.DeepEqual(eStatIDs, statIDs) {
+ t.Errorf("Expecting: %v, received %v", eStatIDs, statIDs)
+ }
+}
diff --git a/utils/consts.go b/utils/consts.go
index db71e8be1..f34f62d6e 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -1019,6 +1019,8 @@ const (
MetaNodeID = "*node_id"
MetaAscending = "*ascending"
MetaDescending = "*descending"
+ MetaDesc = "*desc"
+ MetaAsc = "*asc"
)
// MetaMetrics