mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-22 23:58:44 +05:00
NMItem with support for Config attached, NavigableMap.Set with NMItem
This commit is contained in:
@@ -116,8 +116,9 @@ func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.CfgCdrField) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nM.Set(strings.Split(tplFld.FieldId,
|
||||
utils.HIERARCHY_SEP), out, true)
|
||||
nM.Set(
|
||||
&engine.NMItem{Path: strings.Split(tplFld.FieldId,
|
||||
utils.HIERARCHY_SEP), Data: out}, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -36,15 +36,15 @@ func TestAgReqAsNavigableMap(t *testing.T) {
|
||||
agReq := newAgentRequest(nil, nil,
|
||||
"cgrates.org", filterS)
|
||||
// populate request, emulating the way will be done in HTTPAgent
|
||||
agReq.CGRRequest.Set([]string{utils.CGRID}, utils.Sha1("dsafdsaf",
|
||||
time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), false)
|
||||
agReq.CGRRequest.Set([]string{utils.ToR}, utils.VOICE, false)
|
||||
agReq.CGRRequest.Set([]string{utils.Account}, "1001", false)
|
||||
agReq.CGRRequest.Set([]string{utils.Destination}, "1002", false)
|
||||
agReq.CGRRequest.Set([]string{utils.AnswerTime},
|
||||
time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC), false)
|
||||
agReq.CGRRequest.Set([]string{utils.RequestType}, utils.META_PREPAID, false)
|
||||
agReq.CGRRequest.Set([]string{utils.Usage}, time.Duration(3*time.Minute), false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.CGRID},
|
||||
Data: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String())}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.ToR}, Data: utils.VOICE}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.Account}, Data: "1001"}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.Destination}, Data: "1002"}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.AnswerTime},
|
||||
Data: time.Date(2013, 12, 30, 15, 0, 1, 0, time.UTC)}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.RequestType}, Data: utils.META_PREPAID}, false)
|
||||
agReq.CGRRequest.Set(&engine.NMItem{Path: []string{utils.Usage}, Data: time.Duration(3 * time.Minute)}, false)
|
||||
|
||||
cgrRply := map[string]interface{}{
|
||||
utils.CapAttributes: map[string]interface{}{
|
||||
@@ -99,12 +99,12 @@ func TestAgReqAsNavigableMap(t *testing.T) {
|
||||
"*cgrReply>Error", utils.INFIELD_SEP)},
|
||||
}
|
||||
eMp := engine.NewNavigableMap(nil)
|
||||
eMp.Set([]string{utils.Tenant}, "cgrates.org", true)
|
||||
eMp.Set([]string{utils.Account}, "1001", true)
|
||||
eMp.Set([]string{utils.Destination}, "1002", true)
|
||||
eMp.Set([]string{"RequestedUsage"}, "180", true)
|
||||
eMp.Set([]string{"PaypalAccount"}, "cgrates@paypal.com", true)
|
||||
eMp.Set([]string{"MaxUsage"}, "120", true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{utils.Tenant}, Data: "cgrates.org"}, true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{utils.Account}, Data: "1001"}, true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{utils.Destination}, Data: "1002"}, true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{"RequestedUsage"}, Data: "180"}, true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{"PaypalAccount"}, Data: "cgrates@paypal.com"}, true)
|
||||
eMp.Set(&engine.NMItem{Path: []string{"MaxUsage"}, Data: "120"}, true)
|
||||
if mpOut, err := agReq.AsNavigableMap(tplFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMp, mpOut) {
|
||||
|
||||
@@ -211,7 +211,8 @@ func (ha *HTTPAgent) processRequest(reqProcessor *config.HttpAgntProcCfg,
|
||||
var rplyCDRs string
|
||||
if err = ha.sessionS.Call(utils.SessionSv1ProcessCDR,
|
||||
*cgrEv, &rplyCDRs); err != nil {
|
||||
agReq.CGRReply.Set([]string{utils.Error}, err.Error(), false)
|
||||
agReq.CGRReply.Set(
|
||||
&engine.NMItem{Path: []string{utils.Error}, Data: err.Error()}, false)
|
||||
}
|
||||
}
|
||||
if nM, err := agReq.AsNavigableMap(reqProcessor.ReplyFields); err != nil {
|
||||
|
||||
@@ -67,7 +67,7 @@ func (hU *httpUrlDP) FieldAsInterface(fldPath []string) (data interface{}, err e
|
||||
}
|
||||
err = nil // cancel previous err
|
||||
data = hU.req.FormValue(fldPath[0])
|
||||
hU.cache.Set(fldPath, data, false)
|
||||
hU.cache.Set(&engine.NMItem{Path: fldPath, Data: data}, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -411,6 +411,6 @@ func NewCGRReply(rply engine.NavigableMapper,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp.Set([]string{utils.Error}, "", false) // enforce empty error
|
||||
mp.Set(&engine.NMItem{Path: []string{utils.Error}, Data: ""}, false) // enforce empty error
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ func TestNewCGRReply(t *testing.T) {
|
||||
},
|
||||
}
|
||||
eCgrRply = engine.NewNavigableMap(ev)
|
||||
eCgrRply.Set([]string{utils.Error}, "", false)
|
||||
eCgrRply.Set(&engine.NMItem{Path: []string{utils.Error}, Data: ""}, false)
|
||||
if rpl, err := NewCGRReply(engine.NavigableMapper(ev), nil); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCgrRply, rpl) {
|
||||
|
||||
@@ -39,6 +39,13 @@ func NewNavigableMap(data map[string]interface{}) *NavigableMap {
|
||||
return &NavigableMap{data: data}
|
||||
}
|
||||
|
||||
// NMItem is an item in the NavigableMap
|
||||
type NMItem struct {
|
||||
Path []string // path in map
|
||||
Data interface{} // value of the element
|
||||
Config *config.CfgCdrField // so we can store additional configuration
|
||||
}
|
||||
|
||||
// NavigableMap is a map who's values can be navigated via path
|
||||
// data can be retrieved as ordered
|
||||
// NavigableMap is not thread safe due to performance demands, could come back if needed
|
||||
@@ -48,11 +55,11 @@ type NavigableMap struct {
|
||||
}
|
||||
|
||||
// Add will add items into NavigableMap populating also order
|
||||
func (nM *NavigableMap) Set(path []string, data interface{}, ordered bool) {
|
||||
func (nM *NavigableMap) Set(itm *NMItem, ordered bool) {
|
||||
mp := nM.data
|
||||
for i, spath := range path {
|
||||
if i == len(path)-1 { // last path
|
||||
mp[spath] = data
|
||||
for i, spath := range itm.Path {
|
||||
if i == len(itm.Path)-1 { // last path
|
||||
mp[spath] = itm
|
||||
return
|
||||
}
|
||||
if _, has := mp[spath]; !has {
|
||||
@@ -61,7 +68,7 @@ func (nM *NavigableMap) Set(path []string, data interface{}, ordered bool) {
|
||||
mp = mp[spath].(map[string]interface{}) // so we can check further down
|
||||
}
|
||||
if ordered {
|
||||
nM.order = append(nM.order, path)
|
||||
nM.order = append(nM.order, itm.Path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,12 +83,14 @@ func (nM *NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{},
|
||||
var canCast bool
|
||||
for i, spath := range fldPath {
|
||||
if i == lenPath-1 { // lastElement
|
||||
var has bool
|
||||
fldVal, has = lastMp[spath]
|
||||
itmIface, has := lastMp[spath]
|
||||
if !has {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
return
|
||||
if itm, cast := itmIface.(*NMItem); cast {
|
||||
return itm.Data, nil
|
||||
}
|
||||
return itmIface, nil
|
||||
} else {
|
||||
elmnt, has := lastMp[spath]
|
||||
if !has {
|
||||
@@ -128,21 +137,22 @@ func (nM *NavigableMap) AsMapStringInterface() map[string]interface{} {
|
||||
return nM.data
|
||||
}
|
||||
|
||||
type NMItem struct {
|
||||
Path []string // path in map
|
||||
Data interface{} // value of the element
|
||||
}
|
||||
|
||||
// indexMapElements will recursively go through map and index the element paths into elmns
|
||||
func indexMapElements(mp map[string]interface{}, path []string, elms *[]*NMItem) {
|
||||
for k, v := range mp {
|
||||
vPath := append(path, k)
|
||||
if mpIface, isMap := v.(map[string]interface{}); isMap {
|
||||
indexMapElements(mpIface, vPath, elms)
|
||||
} else {
|
||||
elmsOut := append(*elms, &NMItem{vPath, v})
|
||||
*elms = elmsOut
|
||||
continue
|
||||
}
|
||||
var elmsOut []*NMItem
|
||||
if nMItem, isNMItem := v.(*NMItem); isNMItem {
|
||||
elmsOut = append(*elms, nMItem)
|
||||
} else {
|
||||
elmsOut = append(*elms, &NMItem{Path: vPath, Data: v})
|
||||
}
|
||||
|
||||
*elms = elmsOut
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +178,7 @@ func (nM *NavigableMap) AsNavigableMap(tpl []*config.CfgCdrField) (oNM *Navigabl
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
|
||||
// Merge will update nM with values from a second one
|
||||
func (nM *NavigableMap) Merge(nM2 *NavigableMap) {
|
||||
if nM2 == nil {
|
||||
return
|
||||
@@ -179,3 +190,31 @@ func (nM *NavigableMap) Merge(nM2 *NavigableMap) {
|
||||
nM.order = append(nM.order, nM2.order...)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// MarshalXML implements xml.Marshaler
|
||||
func (nM *NavigableMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
tokens := []xml.Token{start}
|
||||
for _, itm := range nM.Items() {
|
||||
t := xml.StartElement{Name: xml.Name{"", strings.Join(itm.Path, ">")}}
|
||||
tokens = append(tokens, t, xml.CharData(value), xml.EndElement{t.Name})
|
||||
}
|
||||
|
||||
tokens = append(tokens, xml.EndElement{start.Name})
|
||||
|
||||
for _, t := range tokens {
|
||||
err := e.EncodeToken(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// flush to ensure tokens are written
|
||||
err := e.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -148,32 +148,36 @@ func TestNavMapAdd(t *testing.T) {
|
||||
nM := NewNavigableMap(nil)
|
||||
path := []string{"FistLever2", "SecondLevel2", "Field2"}
|
||||
data := "Value2"
|
||||
nM.Set(path, data, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data}, true)
|
||||
path = []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"}
|
||||
data = "Val1"
|
||||
nM.Set(path, data, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data}, true)
|
||||
path = []string{"FistLever2", "Field3"}
|
||||
data = "Value3"
|
||||
nM.Set(path, data, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data}, true)
|
||||
path = []string{"Field4"}
|
||||
data = "Val4"
|
||||
nM.Set(path, data, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data}, true)
|
||||
eNavMap := NavigableMap{
|
||||
data: map[string]interface{}{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
"SecondLevel": map[string]interface{}{
|
||||
"ThirdLevel": map[string]interface{}{
|
||||
"Fld1": "Val1",
|
||||
"Fld1": &NMItem{Path: []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"},
|
||||
Data: "Val1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"FistLever2": map[string]interface{}{
|
||||
"SecondLevel2": map[string]interface{}{
|
||||
"Field2": "Value2",
|
||||
"Field2": &NMItem{Path: []string{"FistLever2", "SecondLevel2", "Field2"},
|
||||
Data: "Value2"},
|
||||
},
|
||||
"Field3": "Value3",
|
||||
"Field3": &NMItem{Path: []string{"FistLever2", "Field3"},
|
||||
Data: "Value3"},
|
||||
},
|
||||
"Field4": "Val4",
|
||||
"Field4": &NMItem{Path: []string{"Field4"},
|
||||
Data: "Val4"},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(nM.data, eNavMap.data) {
|
||||
@@ -190,38 +194,42 @@ func TestNavMapAdd2(t *testing.T) {
|
||||
nM := NewNavigableMap(nil)
|
||||
path := []string{"FistLever2", "SecondLevel2", "Field2"}
|
||||
data := 123
|
||||
nM.Set(path, data, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data}, true)
|
||||
path = []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"}
|
||||
data1 := 123.123
|
||||
nM.Set(path, data1, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data1}, true)
|
||||
path = []string{"FistLever2", "Field3"}
|
||||
data2 := "Value3"
|
||||
nM.Set(path, data2, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data2}, true)
|
||||
path = []string{"Field4"}
|
||||
data3 := &testStruct{
|
||||
Item1: "Ten",
|
||||
Item2: 10,
|
||||
}
|
||||
nM.Set(path, data3, true)
|
||||
nM.Set(&NMItem{Path: path, Data: data3}, true)
|
||||
eNavMap := NavigableMap{
|
||||
data: map[string]interface{}{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
"SecondLevel": map[string]interface{}{
|
||||
"ThirdLevel": map[string]interface{}{
|
||||
"Fld1": 123.123,
|
||||
"Fld1": &NMItem{Path: []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"},
|
||||
Data: 123.123},
|
||||
},
|
||||
},
|
||||
},
|
||||
"FistLever2": map[string]interface{}{
|
||||
"SecondLevel2": map[string]interface{}{
|
||||
"Field2": 123,
|
||||
"Field2": &NMItem{Path: []string{"FistLever2", "SecondLevel2", "Field2"},
|
||||
Data: 123},
|
||||
},
|
||||
"Field3": "Value3",
|
||||
},
|
||||
"Field4": &testStruct{
|
||||
Item1: "Ten",
|
||||
Item2: 10,
|
||||
"Field3": &NMItem{Path: []string{"FistLever2", "Field3"},
|
||||
Data: "Value3"},
|
||||
},
|
||||
"Field4": &NMItem{Path: []string{"Field4"},
|
||||
Data: &testStruct{
|
||||
Item1: "Ten",
|
||||
Item2: 10,
|
||||
}},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(nM.data, eNavMap.data) {
|
||||
|
||||
Reference in New Issue
Block a user