AttributeS with Compile method and attributesIdx, Substitute as utils.RSRParsers

This commit is contained in:
DanB
2018-07-22 11:09:35 +02:00
parent b2764ddf22
commit d66dcd527c
10 changed files with 105 additions and 81 deletions

View File

@@ -168,15 +168,18 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
rply = &AttrSProcessEventReply{
MatchedProfiles: []string{attrPrf.ID},
CGREvent: args.Clone()}
for fldName, initialMp := range attrPrf.attributes {
for fldName, initialMp := range attrPrf.attributesIdx {
initEvValIf, has := args.Event[fldName]
if !has {
anyInitial, hasAny := initialMp[utils.ANY]
if hasAny && anyInitial.Append &&
initialMp[utils.ANY].Substitute.Id() != utils.META_NONE {
rply.CGREvent.Event[fldName] = anyInitial.Substitute.Id()
if hasAny && anyInitial.Append { // add field name
substitute, err := anyInitial.Substitute.ParseEvent(args.Event)
if err != nil {
return nil, err
}
rply.CGREvent.Event[fldName] = substitute
rply.AlteredFields = append(rply.AlteredFields, fldName)
}
rply.AlteredFields = append(rply.AlteredFields, fldName)
continue
}
attrVal, has := initialMp[initEvValIf]
@@ -184,10 +187,14 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
attrVal, has = initialMp[utils.ANY]
}
if has {
if attrVal.Substitute.Id() == utils.META_NONE {
substitute, err := attrVal.Substitute.ParseEvent(args.Event)
if err != nil {
return nil, err
}
if substitute == utils.META_NONE {
delete(rply.CGREvent.Event, fldName)
} else {
rply.CGREvent.Event[fldName] = attrVal.Substitute.Id()
rply.CGREvent.Event[fldName] = substitute
}
rply.AlteredFields = append(rply.AlteredFields, fldName)
}

View File

@@ -36,7 +36,7 @@ var (
utils.META_ANY: &Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1010", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
@@ -101,12 +101,12 @@ var (
&Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1010", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
Weight: 20,
attributes: mapSubstitutes,
Weight: 20,
attributesIdx: mapSubstitutes,
},
&AttributeProfile{
Tenant: config.CgrConfig().DefaultTenant,
@@ -121,12 +121,12 @@ var (
&Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1010", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
Weight: 20,
attributes: mapSubstitutes,
Weight: 20,
attributesIdx: mapSubstitutes,
},
&AttributeProfile{
Tenant: config.CgrConfig().DefaultTenant,
@@ -141,12 +141,12 @@ var (
&Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1010", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
attributes: mapSubstitutes,
Weight: 20,
attributesIdx: mapSubstitutes,
Weight: 20,
},
&AttributeProfile{
Tenant: config.CgrConfig().DefaultTenant,
@@ -161,12 +161,12 @@ var (
&Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1010", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
attributes: mapSubstitutes,
Weight: 20,
attributesIdx: mapSubstitutes,
Weight: 20,
},
}
)
@@ -463,20 +463,14 @@ func TestAttributeIndexer(t *testing.T) {
},
Attributes: []*Attribute{
&Attribute{
FieldName: utils.Account,
Initial: utils.META_ANY,
Append: true,
FieldName: utils.Account,
Initial: utils.META_ANY,
Substitute: utils.NewRSRParsersMustCompile("1010", true),
Append: true,
},
},
Weight: 20,
}
//populate Substitute from attributes
rsrFields, err := utils.ParseRSRFields("^1010", utils.INFIELD_SEP)
if err != nil {
t.Error(err)
}
attrPrf.Attributes[0].Substitute = rsrFields
if err := dmAtr.SetAttributeProfile(attrPrf, true); err != nil {
t.Error(err)
}

View File

@@ -1068,7 +1068,7 @@ func (dm *DataManager) RemoveSupplierProfile(tenant, id, transactionID string, w
}
func (dm *DataManager) GetAttributeProfile(tenant, id string, skipCache bool,
transactionID string) (alsPrf *AttributeProfile, err error) {
transactionID string) (attrPrfl *AttributeProfile, err error) {
tntID := utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := Cache.Get(utils.CacheAttributeProfiles, tntID); ok {
@@ -1078,7 +1078,7 @@ func (dm *DataManager) GetAttributeProfile(tenant, id string, skipCache bool,
return x.(*AttributeProfile), nil
}
}
alsPrf, err = dm.dataDB.GetAttributeProfileDrv(tenant, id)
attrPrfl, err = dm.dataDB.GetAttributeProfileDrv(tenant, id)
if err != nil {
if err == utils.ErrNotFound {
Cache.Set(utils.CacheAttributeProfiles, tntID, nil, nil,
@@ -1086,17 +1086,10 @@ func (dm *DataManager) GetAttributeProfile(tenant, id string, skipCache bool,
}
return nil, err
}
alsPrf.attributes = make(map[string]map[interface{}]*Attribute)
for _, attr := range alsPrf.Attributes {
alsPrf.attributes[attr.FieldName] = make(map[interface{}]*Attribute)
alsPrf.attributes[attr.FieldName][attr.Initial] = &Attribute{
FieldName: attr.FieldName,
Initial: attr.Initial,
Substitute: attr.Substitute,
Append: attr.Append,
}
if err = attrPrfl.Compile(); err != nil {
return nil, err
}
Cache.Set(utils.CacheAttributeProfiles, tntID, alsPrf, nil,
Cache.Set(utils.CacheAttributeProfiles, tntID, attrPrfl, nil,
cacheCommit(transactionID), transactionID)
return
}

View File

@@ -27,7 +27,7 @@ import (
type Attribute struct {
FieldName string
Initial interface{}
Substitute utils.RSRFields
Substitute utils.RSRParsers
Append bool
}
@@ -36,10 +36,37 @@ type AttributeProfile struct {
ID string
Contexts []string // bind this AttributeProfile to multiple contexts
FilterIDs []string
ActivationInterval *utils.ActivationInterval // Activation interval
attributes map[string]map[interface{}]*Attribute // map[FieldName][InitialValue]*Attribute
ActivationInterval *utils.ActivationInterval // Activation interval
Attributes []*Attribute
Weight float64
attributesIdx map[string]map[interface{}]*Attribute // map[FieldName][InitialValue]*Attribute, used as event match index
}
// computeAttributesIndex populates .attributes
func (ap *AttributeProfile) computeAttributesIndex() {
ap.attributesIdx = make(map[string]map[interface{}]*Attribute)
for _, attr := range ap.Attributes {
if _, has := ap.attributesIdx[attr.FieldName]; !has {
ap.attributesIdx[attr.FieldName] = make(map[interface{}]*Attribute)
}
ap.attributesIdx[attr.FieldName][attr.Initial] = attr
}
}
func (ap *AttributeProfile) compileSubstitutes() (err error) {
for _, attr := range ap.Attributes {
if err = attr.Substitute.Compile(); err != nil {
return
}
}
return
}
// Compile is a wrapper for convenience setting up the AttributeProfile
func (ap *AttributeProfile) Compile() error {
ap.computeAttributesIndex()
return ap.compileSubstitutes()
}
func (als *AttributeProfile) TenantID() string {

View File

@@ -2803,31 +2803,17 @@ func APItoAttributeProfile(tpTH *utils.TPAttributeProfile, timezone string) (th
for _, context := range tpTH.Contexts {
th.Contexts = append(th.Contexts, context)
}
th.attributes = make(map[string]map[interface{}]*Attribute)
for _, reqAttr := range tpTH.Attributes {
th.Attributes = append(th.Attributes, &Attribute{
Append: reqAttr.Append,
FieldName: reqAttr.FieldName,
Initial: reqAttr.Initial,
Substitute: utils.RSRFields{
&utils.RSRField{
Id: reqAttr.Substitute,
RSRules: []*utils.ReSearchReplace{}, //from mongo we get empty slice and from redis nil
},
},
})
th.attributes[reqAttr.FieldName] = make(map[interface{}]*Attribute)
th.attributes[reqAttr.FieldName][reqAttr.Initial] = &Attribute{
FieldName: reqAttr.FieldName,
Initial: reqAttr.Initial,
Substitute: utils.RSRFields{
&utils.RSRField{
Id: reqAttr.Substitute,
RSRules: []*utils.ReSearchReplace{}, //from mongo we get empty slice and from redis nil
},
},
Append: reqAttr.Append,
sbstPrsr, err := utils.NewRSRParsers(reqAttr.Substitute, true)
if err != nil {
return nil, err
}
th.Attributes = append(th.Attributes, &Attribute{
Append: reqAttr.Append,
FieldName: reqAttr.FieldName,
Initial: reqAttr.Initial,
Substitute: sbstPrsr,
})
}
if tpTH.ActivationInterval != nil {
if th.ActivationInterval, err = tpTH.ActivationInterval.AsActivationInterval(timezone); err != nil {

View File

@@ -1475,7 +1475,7 @@ func TestAPItoAttributeProfile(t *testing.T) {
mapSubstitutes["FL1"]["In1"] = &Attribute{
FieldName: "FL1",
Initial: "In1",
Substitute: utils.RSRFields{&utils.RSRField{Id: "Al1", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("Al1", true),
Append: true,
}
expected := &AttributeProfile{
@@ -1490,12 +1490,11 @@ func TestAPItoAttributeProfile(t *testing.T) {
&Attribute{
FieldName: "FL1",
Initial: "In1",
Substitute: utils.RSRFields{&utils.RSRField{Id: "Al1", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("Al1", true),
Append: true,
},
},
Weight: 20,
attributes: mapSubstitutes,
Weight: 20,
}
if rcv, err := APItoAttributeProfile(tpAlsPrf, "UTC"); err != nil {
t.Error(err)

View File

@@ -112,13 +112,13 @@ cgrates.org,TestLoader1,lcr,*string:Account:1008;*string:Account:1009,,Subject,*
&engine.Attribute{
FieldName: "Account",
Initial: utils.ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1001", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1001", true),
Append: false,
},
&engine.Attribute{
FieldName: "Subject",
Initial: utils.ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1001", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1001", true),
Append: true,
}},
Weight: 10.0,
@@ -207,7 +207,7 @@ func TestLoaderProcessContentMultiFiles(t *testing.T) {
&engine.Attribute{
FieldName: "Subject",
Initial: utils.ANY,
Substitute: utils.RSRFields{&utils.RSRField{Id: "1001", RSRules: []*utils.ReSearchReplace{}}},
Substitute: utils.NewRSRParsersMustCompile("1001", true),
Append: true,
}},
Weight: 10.0,

View File

@@ -80,7 +80,10 @@ func (m *Migrator) migrateV1Attributes() (err error) {
break
}
if v1Attr != nil {
attrPrf := v1Attr.AsAttributeProfile()
attrPrf, err := v1Attr.AsAttributeProfile()
if err != nil {
return err
}
if m.dryRun != true {
if err := m.dmOut.DataManager().DataDB().SetAttributeProfileDrv(attrPrf); err != nil {
return err
@@ -137,7 +140,7 @@ func (m *Migrator) migrateAttributeProfile() (err error) {
return
}
func (v1AttrPrf v1AttributeProfile) AsAttributeProfile() (attrPrf *engine.AttributeProfile) {
func (v1AttrPrf v1AttributeProfile) AsAttributeProfile() (attrPrf *engine.AttributeProfile, err error) {
attrPrf = &engine.AttributeProfile{
Tenant: v1AttrPrf.Tenant,
ID: v1AttrPrf.ID,
@@ -149,10 +152,14 @@ func (v1AttrPrf v1AttributeProfile) AsAttributeProfile() (attrPrf *engine.Attrib
for _, mp := range v1AttrPrf.Attributes {
for _, attr := range mp {
initIface := utils.StringToInterface(attr.Initial)
sbstPrsr, err := utils.NewRSRParsers(attr.Substitute, true)
if err != nil {
return nil, err
}
attrPrf.Attributes = append(attrPrf.Attributes, &engine.Attribute{
FieldName: attr.FieldName,
Initial: initIface,
Substitute: utils.RSRFields{&utils.RSRField{Id: attr.Substitute}},
Substitute: sbstPrsr,
Append: attr.Append,
})
}

View File

@@ -65,13 +65,15 @@ func Testv1AttributeProfileAsAttributeProfile(t *testing.T) {
&engine.Attribute{
FieldName: "FL1",
Initial: "In1",
Substitute: utils.RSRFields{&utils.RSRField{Id: "Al1"}},
Substitute: utils.NewRSRParsersMustCompile("Al1", true),
Append: true,
},
},
Weight: 20,
}
if !reflect.DeepEqual(attrPrf, v1Attribute.AsAttributeProfile()) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(attrPrf), utils.ToJSON(v1Attribute.AsAttributeProfile()))
if ap, err := v1Attribute.AsAttributeProfile(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(attrPrf, ap) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(attrPrf), utils.ToJSON(ap))
}
}

View File

@@ -56,6 +56,15 @@ func NewRSRParsersMustCompile(parsersRules string, allFiltersMatch bool) (prsrs
// RSRParsers is a set of RSRParser
type RSRParsers []*RSRParser
func (prsrs RSRParsers) Compile() (err error) {
for _, prsr := range prsrs {
if err = prsr.Compile(); err != nil {
return
}
}
return
}
// ParseValue will parse the value out considering converters and filters
func (prsrs RSRParsers) ParseValue(value interface{}) (out string, err error) {
for _, prsr := range prsrs {