From 14515404bbc1cd6bf18deccca962801bab02e840 Mon Sep 17 00:00:00 2001 From: gezimbll Date: Fri, 7 Feb 2025 15:22:43 +0100 Subject: [PATCH] added helper method for repetive logic on GetOpts funcs --- engine/libdynopts.go | 170 ++++++++++++-------------------------- engine/libdynopts_test.go | 39 +++++++++ 2 files changed, 93 insertions(+), 116 deletions(-) diff --git a/engine/libdynopts.go b/engine/libdynopts.go index e0af89df3..621f90d9c 100644 --- a/engine/libdynopts.go +++ b/engine/libdynopts.go @@ -33,19 +33,11 @@ import ( // returns the config option if at least one filter passes or the default value if none of them do func GetFloat64Opts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicFloat64Opt, optNames ...string) (cfgOpt float64, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsFloat64(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return 0, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsFloat64(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -63,19 +55,11 @@ func GetFloat64Opts(ctx *context.Context, tnt string, dP utils.DataProvider, fS // returns the config option if at least one filter passes or the default value if none of them do func GetDurationOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicDurationOpt, optNames ...string) (cfgOpt time.Duration, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsDuration(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return 0, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsDuration(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -93,19 +77,11 @@ func GetDurationOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS // returns the config option if at least one filter passes or the default value if none of them do func GetStringOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicStringOpt, optNames ...string) (cfgOpt string, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsString(opt), nil + } else if !errors.Is(err, utils.ErrNotFound) { return "", err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsString(opt), nil - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -123,18 +99,10 @@ func GetStringOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS * // returns the config option if at least one filter passes or the default value if none of them do func GetTimeOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicStringOpt, tmz string, optNames ...string) (_ time.Time, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { - return - } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsTime(opt, tmz) - } + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsTime(opt, tmz) + } else if !errors.Is(err, utils.ErrNotFound) { + return time.Time{}, err } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { @@ -159,19 +127,11 @@ func GetTimeOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *Fi // returns the config option if at least one filter passes or the default value if none of them do func GetStringSliceOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicStringSliceOpt, dftOpt []string, optNames ...string) (cfgOpt []string, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsStringSlice(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return nil, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsStringSlice(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -189,19 +149,11 @@ func GetStringSliceOpts(ctx *context.Context, tnt string, dP utils.DataProvider, // returns the config option if at least one filter passes or the default value if none of them do func GetIntOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicIntOpt, optNames ...string) (cfgOpt int, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsInt(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return 0, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsInt(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -219,19 +171,11 @@ func GetIntOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *Fil // returns the config option if at least one filter passes or the default value if none of them do func GetBoolOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicBoolOpt, optNames ...string) (cfgOpt bool, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsBool(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return false, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsBool(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -249,19 +193,11 @@ func GetBoolOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *Fi // returns the config option if at least one filter passes or the default value if none of them do func GetDecimalBigOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicDecimalOpt, optNames ...string) (cfgOpt *decimal.Big, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return utils.IfaceAsBig(opt) + } else if !errors.Is(err, utils.ErrNotFound) { return nil, err } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return utils.IfaceAsBig(opt) - } - } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { continue @@ -279,18 +215,10 @@ func GetDecimalBigOpts(ctx *context.Context, tnt string, dP utils.DataProvider, // returns the config option if at least one filter passes or the default value if none of them do func GetInterfaceOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicInterfaceOpt, optNames ...string) (cfgOpt any, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { - return nil, err - } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - return opt, nil - } + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + return opt, nil + } else if !errors.Is(err, utils.ErrNotFound) { + return false, err } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { @@ -309,22 +237,14 @@ func GetInterfaceOpts(ctx *context.Context, tnt string, dP utils.DataProvider, f // returns the config option if at least one filter passes or NOT_FOUND if none of them do func GetIntPointerOpts(ctx *context.Context, tnt string, dP utils.DataProvider, fS *FilterS, dynOpts []*config.DynamicIntPointerOpt, optNames ...string) (cfgOpt *int, err error) { - values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) - if err != nil { - return nil, err - } - opts, err := ConvertOptsToMapStringAny(values) - if err != nil { - return - } - for _, optName := range optNames { - if opt, has := opts[optName]; has { - var value int64 - if value, err = utils.IfaceAsTInt64(opt); err != nil { - return nil, err - } - return utils.IntPointer(int(value)), nil + if opt, err := optIfaceFromDP(dP, optNames); err == nil { + var value int + if value, err = utils.IfaceAsInt(opt); err != nil { + return nil, err } + return utils.IntPointer(value), nil + } else if !errors.Is(err, utils.ErrNotFound) { + return nil, err } for _, opt := range dynOpts { // iterate through the options if !slices.Contains([]string{utils.EmptyString, utils.MetaAny, tnt}, opt.Tenant) { @@ -423,3 +343,21 @@ func ConvertOptsToMapStringAny(in any) (map[string]any, error) { } return out, nil } + +// getOptIfaceFromDP is a helper that returns the first option (as interface{}) found in the data provider +func optIfaceFromDP(dP utils.DataProvider, optNames []string) (any, error) { + values, err := dP.FieldAsInterface([]string{utils.MetaOpts}) + if err != nil { + return nil, err + } + opts, err := ConvertOptsToMapStringAny(values) + if err != nil { + return nil, err + } + for _, optName := range optNames { + if opt, ok := opts[optName]; ok { + return opt, nil + } + } + return nil, utils.ErrNotFound +} diff --git a/engine/libdynopts_test.go b/engine/libdynopts_test.go index 32620475b..d01d994a2 100644 --- a/engine/libdynopts_test.go +++ b/engine/libdynopts_test.go @@ -2668,3 +2668,42 @@ func TestGetBoolOptsCantCastErr(t *testing.T) { } } + +func TestOptIfaceFromDP(t *testing.T) { + tests := []struct { + name string + values []string + exp any + err error + }{ + {name: "TestOptBoolValue", values: []string{utils.MetaProfileIgnoreFilters}, exp: true, err: nil}, + {name: "TestOptBoolValue", values: []string{utils.OptsRoutesIgnoreErrors}, exp: true, err: nil}, + {name: "TestOptFloat64Value", values: []string{utils.OptsAttributesProcessRuns}, exp: 5, err: nil}, + {name: "TestOptIntValue", values: []string{utils.OptsResourcesUnits}, exp: float64(23.1), err: nil}, + {name: "TestOptIntValue", values: []string{utils.OptsAttributesProfileRuns}, exp: 3, err: nil}, + {name: "TestOptStringValue", values: []string{utils.OptsRatesStartTime}, exp: "2021-01-01T00:00:00Z", err: nil}, + {name: "TestOptFloat64Value", values: []string{utils.OptsResourcesUsageID}, exp: "RES1", err: nil}, + {name: "TestFieldNotExist", values: []string{"field1"}, err: utils.ErrNotFound}, + } + cgrEv := utils.MapStorage{ + utils.MetaReq: map[string]any{}, + utils.MetaOpts: map[string]any{ + utils.MetaProfileIgnoreFilters: true, + utils.OptsRoutesIgnoreErrors: true, + utils.OptsAttributesProcessRuns: 5, + utils.OptsAttributesProfileRuns: 3, + utils.OptsRatesStartTime: "2021-01-01T00:00:00Z", + utils.OptsResourcesUsageID: "RES1", + utils.OptsResourcesUnits: 23.1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if rcv, err := optIfaceFromDP(cgrEv, tt.values); err != tt.err { + t.Errorf("expected: <%v>,\nreceived: <%v>", tt.err, err) + } else if rcv != tt.exp { + t.Errorf("expected: <%v>,\nreceived: <%v>", tt.exp, rcv) + } + }) + } +}