From 26cdb571b89cb6a1b088e460d00d8a9ae8ebc012 Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Tue, 14 Nov 2023 07:40:47 -0500 Subject: [PATCH] Upgrade MongoDB driver to 1.13 - Set (but comment) serverAPI options (currently distinct api and create.size BSON field are deprecated + possible others that are untested) - Remove the custom time decoder used for mongo BSON datetime values. The custom decoder was only converting these values into UTC and was not any different from the default time.Time decoder in the MongoDB driver, which also handles BSON string, int64, and document values. - Implement 'buildURL' function to connect to mongo (can also be used for mysql and postgres) - Update function names, variable names, and comments for clarity - Replace 'bsonx.Regex' with the Regex primitive (deprecated since 1.12). - Use simple concatenation instead of Sprintf - Declare 'decimalType' locally, replace global 'decimalType' - Simplify several functions without altering functionality - Converting directly from a D to an M is deprecated. We are now decoding directly in a M. - Used errors.As and errors.Is for proper error comparison and assertion - Revised sloppy reassignments and added missing error checks --- engine/storage_mongo_config.go | 31 +- engine/storage_mongo_datadb.go | 1108 +++++++++++++++----------------- engine/storage_mongo_stordb.go | 770 +--------------------- engine/storage_utils.go | 21 + go.mod | 7 +- go.sum | 27 +- 6 files changed, 600 insertions(+), 1364 deletions(-) diff --git a/engine/storage_mongo_config.go b/engine/storage_mongo_config.go index 515b24013..eb971e657 100644 --- a/engine/storage_mongo_config.go +++ b/engine/storage_mongo_config.go @@ -19,8 +19,14 @@ along with this program. If not, see package engine import ( + "errors" + "reflect" + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/utils" "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/bsoncodec" + "go.mongodb.org/mongo-driver/bson/bsonrw" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) @@ -30,17 +36,30 @@ const ( ) func (ms *MongoStorage) GetSection(ctx *context.Context, section string, val any) error { - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColCfg).FindOne(sctx, bson.M{"section": section}, + return ms.query(context.TODO(), func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColCfg).FindOne(sctx, bson.M{"section": section}, options.FindOne().SetProjection(bson.M{"cfg": 1, "_id": 0 /*"section": 0, */})) tmp := map[string]bson.Raw{} - if err = cur.Decode(&tmp); err != nil { - if err == mongo.ErrNoDocuments { + decodeErr := sr.Decode(&tmp) + if decodeErr != nil { + if errors.Is(decodeErr, mongo.ErrNoDocuments) { return nil } - return + return decodeErr } - return bson.UnmarshalWithRegistry(mongoReg, tmp["cfg"], val) + reg := bson.NewRegistry() + decimalType := reflect.TypeOf(utils.Decimal{}) + reg.RegisterTypeEncoder(decimalType, bsoncodec.ValueEncoderFunc(decimalEncoder)) + reg.RegisterTypeDecoder(decimalType, bsoncodec.ValueDecoderFunc(decimalDecoder)) + + dec, err := bson.NewDecoder(bsonrw.NewBSONDocumentReader(tmp["cfg"])) + if err != nil { + return err + } + if err = dec.SetRegistry(reg); err != nil { + return err + } + return dec.Decode(val) }) } diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go index 2822bb6f6..960c50525 100644 --- a/engine/storage_mongo_datadb.go +++ b/engine/storage_mongo_datadb.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "errors" "fmt" "reflect" "strings" @@ -35,13 +36,12 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsonrw" - "go.mongodb.org/mongo-driver/bson/bsontype" + "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/x/bsonx" ) -// Mongo collections names +// Collection names in MongoDB. const ( ColDst = "destinations" ColRds = "reverse_destinations" @@ -98,58 +98,43 @@ var ( DestinationLow = strings.ToLower(utils.Destination) CostLow = strings.ToLower(utils.Cost) CostSourceLow = strings.ToLower(utils.CostSource) - - tTime = reflect.TypeOf(time.Time{}) - decimalType = reflect.TypeOf(utils.Decimal{}) - - mongoReg *bsoncodec.Registry ) -func init() { - reg := bson.NewRegistryBuilder() - reg.RegisterTypeDecoder(tTime, bsoncodec.ValueDecoderFunc(TimeDecodeValue1)) - reg.RegisterTypeEncoder(decimalType, bsoncodec.ValueEncoderFunc(DecimalEncoder)) - reg.RegisterTypeDecoder(decimalType, bsoncodec.ValueDecoderFunc(DecimalDecoder)) - mongoReg = reg.Build() -} +func decimalEncoder(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { + decimalType := reflect.TypeOf(utils.Decimal{}) -func TimeDecodeValue1(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { - if vr.Type() != bsontype.DateTime { - return fmt.Errorf("cannot decode %v into a time.Time", vr.Type()) + // All encoder implementations should check that val is valid and is of + // the correct type before proceeding. + if !val.IsValid() || val.Type() != decimalType { + return bsoncodec.ValueEncoderError{ + Name: "decimalEncoder", + Types: []reflect.Type{decimalType}, + Received: val, + } } - dt, err := vr.ReadDateTime() + sls, err := val.Interface().(utils.Decimal).MarshalText() if err != nil { return err } - if !val.CanSet() || val.Type() != tTime { - return bsoncodec.ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: val} - } - val.Set(reflect.ValueOf(time.Unix(dt/1000, dt%1000*1000000).UTC())) - return nil -} - -func DecimalEncoder(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { - if val.Kind() != reflect.Struct { - return bsoncodec.ValueEncoderError{Name: "DecimalEncoder", Kinds: []reflect.Kind{reflect.Struct}, Received: val} - } - d, ok := val.Interface().(utils.Decimal) - if !ok { - return fmt.Errorf("cannot cast <%+v> to ", val.Interface()) - } - sls, err := d.MarshalText() - if err != nil { - return err - } return vw.WriteBinary(sls) } -func DecimalDecoder(ec bsoncodec.DecodeContext, vw bsonrw.ValueReader, val reflect.Value) error { - if !val.CanSet() || val.Type() != decimalType { - return bsoncodec.ValueEncoderError{Name: "DecimalDecoder", Kinds: []reflect.Kind{reflect.Struct}, Received: val} +func decimalDecoder(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { + decimalType := reflect.TypeOf(utils.Decimal{}) + + // All decoder implementations should check that val is valid, settable, + // and is of the correct kind before proceeding. + if !val.IsValid() || !val.CanSet() || val.Type() != decimalType { + return bsoncodec.ValueDecoderError{ + Name: "decimalDecoder", + Types: []reflect.Type{decimalType}, + Received: val, + } } - data, _, err := vw.ReadBinary() + + data, _, err := vr.ReadBinary() if err != nil { return err } @@ -161,74 +146,72 @@ func DecimalDecoder(ec bsoncodec.DecodeContext, vw bsonrw.ValueReader, val refle return nil } -// NewMongoStorage givese new mongo driver -func NewMongoStorage(host, port, db, user, pass, mrshlerStr, storageType string, - cdrsIndexes []string, ttl time.Duration) (ms *MongoStorage, err error) { - url := host - if port != "0" { - url += ":" + port - } - if user != "" && pass != "" { - url = fmt.Sprintf("%s:%s@%s", user, pass, url) - } - var dbName string - if db != "" { - url += "/" + db - dbName = strings.Split(db, "?")[0] // remove extra info after ? - } - ctx := context.TODO() - url = "mongodb://" + url - opt := options.Client(). - ApplyURI(url). - SetRegistry(mongoReg). - SetServerSelectionTimeout(ttl). - SetRetryWrites(false) // set this option to false because as default it is on true - - client, err := mongo.NewClient(opt) - // client, err := mongo.NewClient(url) - +// NewMongoStorage initializes a new MongoDB storage instance with provided connection parameters and settings. +// Returns an error if the setup fails. +func NewMongoStorage(host, port, db, user, pass, mrshlerStr string, storageType string, + cdrsIndexes []string, ttl time.Duration) (*MongoStorage, error) { + url, err := buildURL("mongodb", host, port, db, user, pass) if err != nil { return nil, err } - err = client.Connect(ctx) - if err != nil { - return nil, err - } - mrshler, err := utils.NewMarshaler(mrshlerStr) - if err != nil { - return nil, err - } - - ms = &MongoStorage{ - client: client, + mongoStorage := &MongoStorage{ ctxTTL: ttl, - db: dbName, - storageType: storageType, - ms: mrshler, cdrsIndexes: cdrsIndexes, + storageType: storageType, + counter: utils.NewCounter(time.Now().UnixNano(), 0), + } + reg := bson.NewRegistry() + decimalType := reflect.TypeOf(utils.Decimal{}) + reg.RegisterTypeEncoder(decimalType, bsoncodec.ValueEncoderFunc(decimalEncoder)) + reg.RegisterTypeDecoder(decimalType, bsoncodec.ValueDecoderFunc(decimalDecoder)) + // serverAPI := options.ServerAPI(options.ServerAPIVersion1).SetStrict(true).SetDeprecationErrors(true) + opts := options.Client(). + ApplyURI(url.String()). + SetRegistry(reg). + SetServerSelectionTimeout(mongoStorage.ctxTTL). + SetRetryWrites(false) // default is true + // SetServerAPIOptions(serverAPI) + + // Create a new client and connect to the server + ctx := context.TODO() + mongoStorage.client, err = mongo.Connect(ctx, opts) + if err != nil { + return nil, err } - if err = ms.query(ctx, func(sctx mongo.SessionContext) error { - cols, err := ms.client.Database(dbName).ListCollectionNames(sctx, bson.D{}) + mongoStorage.ms, err = utils.NewMarshaler(mrshlerStr) + if err != nil { + return nil, err + } + if db != "" { + // Populate ms.db with the url path after trimming everything after '?'. + mongoStorage.db = strings.Split(db, "?")[0] + } + + err = mongoStorage.query(ctx, func(sctx mongo.SessionContext) error { + // Create indexes only if the database is empty or only the version table is present. + cols, err := mongoStorage.client.Database(mongoStorage.db). + ListCollectionNames(sctx, bson.D{}) if err != nil { return err } empty := true - for _, col := range cols { // create indexes only if database is empty or only version table is present + for _, col := range cols { if col != ColVer { empty = false break } } if empty { - return ms.EnsureIndexes() + return mongoStorage.EnsureIndexes() } return nil - }); err != nil { + }) + + if err != nil { return nil, err } - ms.cnter = utils.NewCounter(time.Now().UnixNano(), 0) - return + return mongoStorage, nil } // MongoStorage struct for new mongo driver @@ -237,13 +220,13 @@ type MongoStorage struct { ctxTTL time.Duration ctxTTLMutex sync.RWMutex // used for TTL reload db string - storageType string // datadb, stordb + storageType string // DataDB/StorDB ms utils.Marshaler cdrsIndexes []string - cnter *utils.Counter + counter *utils.Counter } -func (ms *MongoStorage) query(ctx *context.Context, argfunc func(ctx mongo.SessionContext) error) (err error) { +func (ms *MongoStorage) query(ctx *context.Context, argfunc func(ctx mongo.SessionContext) error) error { ms.ctxTTLMutex.RLock() ctxSession, ctxSessionCancel := context.WithTimeout(ctx, ms.ctxTTL) ms.ctxTTLMutex.RUnlock() @@ -251,29 +234,29 @@ func (ms *MongoStorage) query(ctx *context.Context, argfunc func(ctx mongo.Sessi return ms.client.UseSession(ctxSession, argfunc) } -// IsDataDB returns if the storeage is used for DataDb +// IsDataDB returns whether or not the storage is used for DataDB. func (ms *MongoStorage) IsDataDB() bool { return ms.storageType == utils.DataDB } -// SetTTL set the context TTL used for queries (is thread safe) +// SetTTL sets the context TTL used for queries (Thread-safe). func (ms *MongoStorage) SetTTL(ttl time.Duration) { ms.ctxTTLMutex.Lock() ms.ctxTTL = ttl ms.ctxTTLMutex.Unlock() } -func (ms *MongoStorage) enusureIndex(colName string, uniq bool, keys ...string) error { +func (ms *MongoStorage) ensureIndex(colName string, uniq bool, keys ...string) error { return ms.query(context.TODO(), func(sctx mongo.SessionContext) error { col := ms.getCol(colName) - io := options.Index().SetUnique(uniq) + indexOptions := options.Index().SetUnique(uniq) doc := make(bson.D, 0) for _, k := range keys { doc = append(doc, bson.E{Key: k, Value: 1}) } _, err := col.Indexes().CreateOne(sctx, mongo.IndexModel{ Keys: doc, - Options: io, + Options: indexOptions, }) return err }) @@ -291,123 +274,101 @@ func (ms *MongoStorage) getCol(col string) *mongo.Collection { return ms.client.Database(ms.db).Collection(col) } -// GetContext returns the context used for the current DB +// GetContext returns the context used for the current database. func (ms *MongoStorage) GetContext() *context.Context { return context.TODO() } func isNotFound(err error) bool { - de, ok := err.(mongo.CommandError) - if !ok { // if still can't converted to the mongo.CommandError check if error do not contains message - return strings.Contains(err.Error(), "ns not found") + var de *mongo.CommandError + + if errors.As(err, &de) { + return de.Code == 26 || de.Message == "ns not found" } - return de.Code == 26 || de.Message == "ns not found" + + // If the error cannot be converted to mongo.CommandError + // check if the error message contains "ns not found" + return strings.Contains(err.Error(), "ns not found") } -func (ms *MongoStorage) ensureIndexesForCol(col string) (err error) { // exported for migrator - if err = ms.dropAllIndexesForCol(col); err != nil && !isNotFound(err) { // make sure you do not have indexes - return +func (ms *MongoStorage) ensureIndexesForCol(col string) error { // exported for migrator + err := ms.dropAllIndexesForCol(col) + if err != nil && !isNotFound(err) { // make sure you do not have indexes + return err } - err = nil switch col { case ColAct, ColApl, ColAAp, ColAtr, ColRpl, ColDst, ColRds, ColLht, ColIndx: - if err = ms.enusureIndex(col, true, "key"); err != nil { - return - } + err = ms.ensureIndex(col, true, "key") case ColRsP, ColRes, ColSqs, ColSqp, ColTps, ColThs, ColRts, ColAttr, ColFlt, ColCpp, ColDpp, ColDph, ColRpp, ColApp, ColAnp: - if err = ms.enusureIndex(col, true, "tenant", "id"); err != nil { - return - } + err = ms.ensureIndex(col, true, "tenant", "id") case ColRpf, ColShg, ColAcc: - if err = ms.enusureIndex(col, true, "id"); err != nil { - return - } - + err = ms.ensureIndex(col, true, "id") case utils.CDRsTBL: - if err = ms.enusureIndex(col, true, MetaOriginLow, RunIDLow, - OriginIDLow); err != nil { - return - } - for _, idxKey := range ms.cdrsIndexes { - if err = ms.enusureIndex(col, false, idxKey); err != nil { - return + err = ms.ensureIndex(col, true, MetaOriginLow, RunIDLow, + OriginIDLow) + if err == nil { + for _, idxKey := range ms.cdrsIndexes { + err = ms.ensureIndex(col, false, idxKey) + if err != nil { + break + } } } - case utils.SessionCostsTBL: - if err = ms.enusureIndex(col, true, MetaOriginLow, - RunIDLow); err != nil { - return - } - if err = ms.enusureIndex(col, false, OriginHostLow, - OriginIDLow); err != nil { - return - } - if err = ms.enusureIndex(col, false, RunIDLow, - OriginIDLow); err != nil { - return - } } - return + return err } -// EnsureIndexes creates db indexes -func (ms *MongoStorage) EnsureIndexes(cols ...string) (err error) { - if len(cols) != 0 { - for _, col := range cols { - if err = ms.ensureIndexesForCol(col); err != nil { - return - } - } - return - } - if ms.storageType == utils.DataDB { - for _, col := range []string{ColAct, ColApl, ColAAp, ColAtr, - ColRpl, ColDst, ColRds, ColLht, ColIndx, ColRsP, ColRes, ColSqs, ColSqp, - ColTps, ColThs, ColRts, ColAttr, ColFlt, ColCpp, ColDpp, ColRpp, ColApp, - ColRpf, ColShg, ColAcc, ColAnp} { - if err = ms.ensureIndexesForCol(col); err != nil { - return +// EnsureIndexes creates database indexes for the specified collections. +func (ms *MongoStorage) EnsureIndexes(cols ...string) error { + if len(cols) == 0 { + if ms.IsDataDB() { + cols = []string{ + ColAct, ColApl, ColAAp, ColAtr, ColRpl, ColDst, ColRds, ColLht, ColIndx, + ColRsP, ColRes, ColSqs, ColSqp, ColTps, ColThs, ColRts, ColAttr, ColFlt, + ColCpp, ColDpp, ColRpp, ColApp, ColRpf, ColShg, ColAcc, ColAnp, } + } else { + cols = []string{utils.CDRsTBL} } } - if ms.storageType == utils.StorDB { - if err = ms.ensureIndexesForCol(utils.CDRsTBL); err != nil { - return + for _, col := range cols { + if err := ms.ensureIndexesForCol(col); err != nil { + return err } } - return + return nil } -// Close disconects the client +// Close disconnects the MongoDB client. func (ms *MongoStorage) Close() { if err := ms.client.Disconnect(context.TODO()); err != nil { utils.Logger.Err(fmt.Sprintf(" Error on disconect:%s", err)) } } -// Flush drops the datatable -func (ms *MongoStorage) Flush(ignore string) (err error) { +// Flush drops the datatable and recreates the indexes. +func (ms *MongoStorage) Flush(_ string) error { return ms.query(context.TODO(), func(sctx mongo.SessionContext) error { - if err = ms.client.Database(ms.db).Drop(sctx); err != nil { + if err := ms.client.Database(ms.db).Drop(sctx); err != nil { return err } - return ms.EnsureIndexes() // recreate the indexes + return ms.EnsureIndexes() }) } -// DB returnes a database object +// DB returns the database object associated with the MongoDB client. func (ms *MongoStorage) DB() *mongo.Database { return ms.client.Database(ms.db) } -// SelectDatabase selects the database -func (ms *MongoStorage) SelectDatabase(dbName string) (err error) { +// SelectDatabase selects the specified database. +func (ms *MongoStorage) SelectDatabase(dbName string) error { ms.db = dbName - return + return nil } -// IsDBEmpty implementation -func (ms *MongoStorage) IsDBEmpty() (resp bool, err error) { +// IsDBEmpty checks if the database is empty by verifying if each collection is empty. +func (ms *MongoStorage) IsDBEmpty() (isEmpty bool, err error) { err = ms.query(context.TODO(), func(sctx mongo.SessionContext) error { cols, err := ms.DB().ListCollectionNames(sctx, bson.D{}) if err != nil { @@ -417,28 +378,33 @@ func (ms *MongoStorage) IsDBEmpty() (resp bool, err error) { if col == utils.CDRsTBL { // ignore cdrs collection continue } - var count int64 - if count, err = ms.getCol(col).CountDocuments(sctx, bson.D{}, options.Count().SetLimit(1)); err != nil { // check if collection is empty so limit the count to 1 + count, err := ms.getCol(col).CountDocuments(sctx, bson.D{}, options.Count().SetLimit(1)) // limiting the count to 1 since we are only checking if the collection is empty + if err != nil { return err } if count != 0 { return nil } } - resp = true + isEmpty = true return nil }) - return resp, err + return isEmpty, err } -func (ms *MongoStorage) getField2(sctx mongo.SessionContext, col, prefix, subject string, tntID *utils.TenantID) (result []string, err error) { +func (ms *MongoStorage) getAllKeysMatchingTenantID(sctx mongo.SessionContext, col, prefix string, tntID *utils.TenantID) (result []string, err error) { idResult := struct{ Tenant, ID string }{} elem := bson.M{} if tntID.Tenant != "" { elem["tenant"] = tntID.Tenant } if tntID.ID != "" { - elem["id"] = bsonx.Regex(tntID.ID, "") + elem["id"] = primitive.Regex{ + + // Note: Before replacing subject with the ID within TenantID, + // we used to prefix the pattern with a caret(^). + Pattern: tntID.ID, + } } iter, err := ms.getCol(col).Find(sctx, elem, @@ -456,12 +422,16 @@ func (ms *MongoStorage) getField2(sctx mongo.SessionContext, col, prefix, subjec return result, iter.Close(sctx) } -func (ms *MongoStorage) getField3(sctx mongo.SessionContext, col, prefix, field string) (result []string, err error) { - fieldResult := bson.D{} - iter, err := ms.getCol(col).Find(sctx, - bson.M{field: bsonx.Regex(fmt.Sprintf("^%s", prefix), "")}, +func (ms *MongoStorage) getAllIndexKeys(sctx mongo.SessionContext, prefix string) (keys []string, err error) { + fieldResult := bson.M{} + iter, err := ms.getCol(ColIndx).Find(sctx, + bson.M{ + "key": primitive.Regex{ + Pattern: "^" + prefix, + }, + }, options.Find().SetProjection( - bson.M{field: 1}, + bson.M{"key": 1}, ), ) if err != nil { @@ -472,85 +442,83 @@ func (ms *MongoStorage) getField3(sctx mongo.SessionContext, col, prefix, field if err != nil { return } - result = append(result, fieldResult.Map()[field].(string)) + keys = append(keys, fieldResult["key"].(string)) } - return result, iter.Close(sctx) + return keys, iter.Close(sctx) } // GetKeysForPrefix implementation -func (ms *MongoStorage) GetKeysForPrefix(ctx *context.Context, prefix string) (result []string, err error) { - var category, subject string +func (ms *MongoStorage) GetKeysForPrefix(ctx *context.Context, prefix string) (keys []string, err error) { keyLen := len(utils.AccountPrefix) if len(prefix) < keyLen { return nil, fmt.Errorf("unsupported prefix in GetKeysForPrefix: %q", prefix) } - category = prefix[:keyLen] // prefix length + category := prefix[:keyLen] // prefix length tntID := utils.NewTenantID(prefix[keyLen:]) - subject = fmt.Sprintf("^%s", prefix[keyLen:]) // old way, no tenant support - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { + err = ms.query(ctx, func(sctx mongo.SessionContext) (qryErr error) { switch category { case utils.ResourceProfilesPrefix: - result, err = ms.getField2(sctx, ColRsP, utils.ResourceProfilesPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRsP, utils.ResourceProfilesPrefix, tntID) case utils.ResourcesPrefix: - result, err = ms.getField2(sctx, ColRes, utils.ResourcesPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRes, utils.ResourcesPrefix, tntID) case utils.StatQueuePrefix: - result, err = ms.getField2(sctx, ColSqs, utils.StatQueuePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColSqs, utils.StatQueuePrefix, tntID) case utils.StatQueueProfilePrefix: - result, err = ms.getField2(sctx, ColSqp, utils.StatQueueProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColSqp, utils.StatQueueProfilePrefix, tntID) case utils.FilterPrefix: - result, err = ms.getField2(sctx, ColFlt, utils.FilterPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColFlt, utils.FilterPrefix, tntID) case utils.ThresholdPrefix: - result, err = ms.getField2(sctx, ColThs, utils.ThresholdPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColThs, utils.ThresholdPrefix, tntID) case utils.ThresholdProfilePrefix: - result, err = ms.getField2(sctx, ColTps, utils.ThresholdProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColTps, utils.ThresholdProfilePrefix, tntID) case utils.RouteProfilePrefix: - result, err = ms.getField2(sctx, ColRts, utils.RouteProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRts, utils.RouteProfilePrefix, tntID) case utils.AttributeProfilePrefix: - result, err = ms.getField2(sctx, ColAttr, utils.AttributeProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColAttr, utils.AttributeProfilePrefix, tntID) case utils.ChargerProfilePrefix: - result, err = ms.getField2(sctx, ColCpp, utils.ChargerProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColCpp, utils.ChargerProfilePrefix, tntID) case utils.DispatcherProfilePrefix: - result, err = ms.getField2(sctx, ColDpp, utils.DispatcherProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColDpp, utils.DispatcherProfilePrefix, tntID) case utils.RateProfilePrefix: - result, err = ms.getField2(sctx, ColRpp, utils.RateProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRpp, utils.RateProfilePrefix, tntID) case utils.ActionProfilePrefix: - result, err = ms.getField2(sctx, ColApp, utils.ActionProfilePrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColApp, utils.ActionProfilePrefix, tntID) case utils.AccountPrefix: - result, err = ms.getField2(sctx, ColAnp, utils.AccountPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColAnp, utils.AccountPrefix, tntID) case utils.DispatcherHostPrefix: - result, err = ms.getField2(sctx, ColDph, utils.DispatcherHostPrefix, subject, tntID) + keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColDph, utils.DispatcherHostPrefix, tntID) case utils.AttributeFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.AttributeFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.AttributeFilterIndexes) case utils.ResourceFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.ResourceFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.ResourceFilterIndexes) case utils.StatFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.StatFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.StatFilterIndexes) case utils.ThresholdFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.ThresholdFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.ThresholdFilterIndexes) case utils.RouteFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.RouteFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.RouteFilterIndexes) case utils.ChargerFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.ChargerFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.ChargerFilterIndexes) case utils.DispatcherFilterIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.DispatcherFilterIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.DispatcherFilterIndexes) case utils.ActionPlanIndexes: - result, err = ms.getField3(sctx, ColIndx, utils.ActionPlanIndexes, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.ActionPlanIndexes) case utils.ActionProfilesFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.ActionProfilesFilterIndexPrfx, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.ActionProfilesFilterIndexPrfx) case utils.AccountFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.AccountFilterIndexPrfx, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.AccountFilterIndexPrfx) case utils.RateProfilesFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.RateProfilesFilterIndexPrfx, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.RateProfilesFilterIndexPrfx) case utils.RateFilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.RateFilterIndexPrfx, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.RateFilterIndexPrfx) case utils.FilterIndexPrfx: - result, err = ms.getField3(sctx, ColIndx, utils.FilterIndexPrfx, "key") + keys, qryErr = ms.getAllIndexKeys(sctx, utils.FilterIndexPrfx) default: - err = fmt.Errorf("unsupported prefix in GetKeysForPrefix: %q", prefix) + qryErr = fmt.Errorf("unsupported prefix in GetKeysForPrefix: %q", prefix) } - return err + return qryErr }) - return + return keys, err } func (ms *MongoStorage) HasDataDrv(ctx *context.Context, category, subject, tenant string) (has bool, err error) { @@ -596,16 +564,20 @@ func (ms *MongoStorage) HasDataDrv(ctx *context.Context, category, subject, tena return has, err } -// Limit will only retrieve the last n items out of history, newest first +// GetLoadHistory retrieves the last n items from the load history, newest first. func (ms *MongoStorage) GetLoadHistory(limit int, skipCache bool, - transactionID string) (loadInsts []*utils.LoadInstance, err error) { + transactionID string) ([]*utils.LoadInstance, error) { if limit == 0 { return nil, nil } if !skipCache { - if x, ok := Cache.Get(utils.LoadInstKey, ""); ok { + x, ok := Cache.Get(utils.LoadInstKey, "") + if ok { if x != nil { - items := x.([]*utils.LoadInstance) + items, ok := x.([]*utils.LoadInstance) + if !ok { + return nil, utils.ErrCastFailed + } if len(items) < limit || limit == -1 { return items, nil } @@ -618,66 +590,65 @@ func (ms *MongoStorage) GetLoadHistory(limit int, skipCache bool, Key string Value []*utils.LoadInstance } - err = ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColLht).FindOne(sctx, bson.M{"key": utils.LoadInstKey}) - if err := cur.Decode(&kv); err != nil { - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err + err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { + sr := ms.getCol(ColLht).FindOne(sctx, bson.M{"key": utils.LoadInstKey}) + decodeErr := sr.Decode(&kv) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) cCommit := cacheCommit(transactionID) if err == nil { - loadInsts = kv.Value if errCh := Cache.Remove(context.TODO(), utils.LoadInstKey, "", cCommit, transactionID); errCh != nil { return nil, errCh } - if errCh := Cache.Set(context.TODO(), utils.LoadInstKey, "", loadInsts, nil, cCommit, transactionID); errCh != nil { + if errCh := Cache.Set(context.TODO(), utils.LoadInstKey, "", kv.Value, nil, cCommit, transactionID); errCh != nil { return nil, errCh } } - if len(loadInsts) < limit || limit == -1 { - return loadInsts, nil + if len(kv.Value) < limit || limit == -1 { + return kv.Value, nil } - return loadInsts[:limit], nil + return kv.Value[:limit], nil } -// Adds a single load instance to load history +// AddLoadHistory adds a single load instance to the load history. func (ms *MongoStorage) AddLoadHistory(ldInst *utils.LoadInstance, loadHistSize int, transactionID string) error { if loadHistSize == 0 { // Load history disabled return nil } - // get existing load history + + // Get existing load history. var existingLoadHistory []*utils.LoadInstance var kv struct { Key string Value []*utils.LoadInstance } - if err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColLht).FindOne(sctx, bson.M{"key": utils.LoadInstKey}) - if err := cur.Decode(&kv); err != nil { - if err == mongo.ErrNoDocuments { - return nil // utils.ErrNotFound - } - return err + err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { + sr := ms.getCol(ColLht).FindOne(sctx, bson.M{"key": utils.LoadInstKey}) + decodeErr := sr.Decode(&kv) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return nil // utils.ErrNotFound } - return nil - }); err != nil { + return decodeErr + }) + if err != nil { return err } if kv.Value != nil { existingLoadHistory = kv.Value } - err := guardian.Guardian.Guard(context.TODO(), func(ctx *context.Context) error { // Make sure we do it locked since other instance can modify history while we read it - // insert on first position + + // Make sure we do it locked since other instances can modify the history while we read it. + err = guardian.Guardian.Guard(context.TODO(), func(ctx *context.Context) error { + + // Insert at the first position. existingLoadHistory = append(existingLoadHistory, nil) copy(existingLoadHistory[1:], existingLoadHistory[0:]) existingLoadHistory[0] = ldInst - //check length histLen := len(existingLoadHistory) if histLen >= loadHistSize { // Have hit maximum history allowed, remove oldest element in order to add new one existingLoadHistory = existingLoadHistory[:loadHistSize] @@ -701,25 +672,22 @@ func (ms *MongoStorage) AddLoadHistory(ldInst *utils.LoadInstance, return err } -func (ms *MongoStorage) GetResourceProfileDrv(ctx *context.Context, tenant, id string) (rp *ResourceProfile, err error) { - rp = new(ResourceProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColRsP).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(rp); err != nil { - rp = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetResourceProfileDrv(ctx *context.Context, tenant, id string) (*ResourceProfile, error) { + rsProfile := new(ResourceProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColRsP).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(rsProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return rsProfile, err } -func (ms *MongoStorage) SetResourceProfileDrv(ctx *context.Context, rp *ResourceProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColRsP).UpdateOne(sctx, bson.M{"tenant": rp.Tenant, "id": rp.ID}, +func (ms *MongoStorage) SetResourceProfileDrv(ctx *context.Context, rp *ResourceProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColRsP).UpdateOne(sctx, bson.M{"tenant": rp.Tenant, "id": rp.ID}, bson.M{"$set": rp}, options.Update().SetUpsert(true), ) @@ -727,8 +695,8 @@ func (ms *MongoStorage) SetResourceProfileDrv(ctx *context.Context, rp *Resource }) } -func (ms *MongoStorage) RemoveResourceProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveResourceProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColRsP).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -737,25 +705,22 @@ func (ms *MongoStorage) RemoveResourceProfileDrv(ctx *context.Context, tenant, i }) } -func (ms *MongoStorage) GetResourceDrv(ctx *context.Context, tenant, id string) (r *Resource, err error) { - r = new(Resource) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColRes).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetResourceDrv(ctx *context.Context, tenant, id string) (*Resource, error) { + resource := new(Resource) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColRes).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(resource) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return resource, err } -func (ms *MongoStorage) SetResourceDrv(ctx *context.Context, r *Resource) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColRes).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetResourceDrv(ctx *context.Context, r *Resource) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColRes).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -763,8 +728,8 @@ func (ms *MongoStorage) SetResourceDrv(ctx *context.Context, r *Resource) (err e }) } -func (ms *MongoStorage) RemoveResourceDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveResourceDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColRes).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -774,26 +739,23 @@ func (ms *MongoStorage) RemoveResourceDrv(ctx *context.Context, tenant, id strin } // GetStatQueueProfileDrv retrieves a StatQueueProfile from dataDB -func (ms *MongoStorage) GetStatQueueProfileDrv(ctx *context.Context, tenant string, id string) (sq *StatQueueProfile, err error) { - sq = new(StatQueueProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColSqp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(sq); err != nil { - sq = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetStatQueueProfileDrv(ctx *context.Context, tenant string, id string) (*StatQueueProfile, error) { + sqProfile := new(StatQueueProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColSqp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(sqProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return sqProfile, err } // SetStatQueueProfileDrv stores a StatsQueue into DataDB -func (ms *MongoStorage) SetStatQueueProfileDrv(ctx *context.Context, sq *StatQueueProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColSqp).UpdateOne(sctx, bson.M{"tenant": sq.Tenant, "id": sq.ID}, +func (ms *MongoStorage) SetStatQueueProfileDrv(ctx *context.Context, sq *StatQueueProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColSqp).UpdateOne(sctx, bson.M{"tenant": sq.Tenant, "id": sq.ID}, bson.M{"$set": sq}, options.Update().SetUpsert(true), ) @@ -802,8 +764,8 @@ func (ms *MongoStorage) SetStatQueueProfileDrv(ctx *context.Context, sq *StatQue } // RemStatQueueProfileDrv removes a StatsQueue from dataDB -func (ms *MongoStorage) RemStatQueueProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemStatQueueProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColSqp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -813,33 +775,30 @@ func (ms *MongoStorage) RemStatQueueProfileDrv(ctx *context.Context, tenant, id } // GetStatQueueDrv retrieves a StoredStatQueue -func (ms *MongoStorage) GetStatQueueDrv(ctx *context.Context, tenant, id string) (sq *StatQueue, err error) { +func (ms *MongoStorage) GetStatQueueDrv(ctx *context.Context, tenant, id string) (*StatQueue, error) { ssq := new(StoredStatQueue) - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColSqs).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(ssq); err != nil { - sq = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColSqs).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(ssq) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil - }); err != nil { - return + return decodeErr + }) + if err != nil { + return nil, err } - sq, err = ssq.AsStatQueue(ms.ms) - return + return ssq.AsStatQueue(ms.ms) } // SetStatQueueDrv stores the metrics for a StoredStatQueue func (ms *MongoStorage) SetStatQueueDrv(ctx *context.Context, ssq *StoredStatQueue, sq *StatQueue) (err error) { if ssq == nil { if ssq, err = NewStoredStatQueue(sq, ms.ms); err != nil { - return + return err } } - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { + return ms.query(ctx, func(sctx mongo.SessionContext) error { _, err = ms.getCol(ColSqs).UpdateOne(sctx, bson.M{"tenant": ssq.Tenant, "id": ssq.ID}, bson.M{"$set": ssq}, options.Update().SetUpsert(true), @@ -849,8 +808,8 @@ func (ms *MongoStorage) SetStatQueueDrv(ctx *context.Context, ssq *StoredStatQue } // RemStatQueueDrv removes stored metrics for a StoredStatQueue -func (ms *MongoStorage) RemStatQueueDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemStatQueueDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColSqs).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -860,26 +819,23 @@ func (ms *MongoStorage) RemStatQueueDrv(ctx *context.Context, tenant, id string) } // GetThresholdProfileDrv retrieves a ThresholdProfile from dataDB -func (ms *MongoStorage) GetThresholdProfileDrv(ctx *context.Context, tenant, ID string) (tp *ThresholdProfile, err error) { - tp = new(ThresholdProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColTps).FindOne(sctx, bson.M{"tenant": tenant, "id": ID}) - if err := cur.Decode(tp); err != nil { - tp = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetThresholdProfileDrv(ctx *context.Context, tenant, ID string) (*ThresholdProfile, error) { + thProfile := new(ThresholdProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColTps).FindOne(sctx, bson.M{"tenant": tenant, "id": ID}) + decodeErr := sr.Decode(thProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return thProfile, err } // SetThresholdProfileDrv stores a ThresholdProfile into DataDB -func (ms *MongoStorage) SetThresholdProfileDrv(ctx *context.Context, tp *ThresholdProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColTps).UpdateOne(sctx, bson.M{"tenant": tp.Tenant, "id": tp.ID}, +func (ms *MongoStorage) SetThresholdProfileDrv(ctx *context.Context, tp *ThresholdProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColTps).UpdateOne(sctx, bson.M{"tenant": tp.Tenant, "id": tp.ID}, bson.M{"$set": tp}, options.Update().SetUpsert(true), ) return err @@ -887,8 +843,8 @@ func (ms *MongoStorage) SetThresholdProfileDrv(ctx *context.Context, tp *Thresho } // RemoveThresholdProfile removes a ThresholdProfile from dataDB/cache -func (ms *MongoStorage) RemThresholdProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemThresholdProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColTps).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -897,25 +853,22 @@ func (ms *MongoStorage) RemThresholdProfileDrv(ctx *context.Context, tenant, id }) } -func (ms *MongoStorage) GetThresholdDrv(ctx *context.Context, tenant, id string) (r *Threshold, err error) { - r = new(Threshold) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColThs).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetThresholdDrv(ctx *context.Context, tenant, id string) (*Threshold, error) { + th := new(Threshold) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColThs).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(th) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return th, err } -func (ms *MongoStorage) SetThresholdDrv(ctx *context.Context, r *Threshold) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColThs).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetThresholdDrv(ctx *context.Context, r *Threshold) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColThs).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -923,8 +876,8 @@ func (ms *MongoStorage) SetThresholdDrv(ctx *context.Context, r *Threshold) (err }) } -func (ms *MongoStorage) RemoveThresholdDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveThresholdDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColThs).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -933,26 +886,25 @@ func (ms *MongoStorage) RemoveThresholdDrv(ctx *context.Context, tenant, id stri }) } -func (ms *MongoStorage) GetFilterDrv(ctx *context.Context, tenant, id string) (r *Filter, err error) { - r = new(Filter) - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColFlt).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetFilterDrv(ctx *context.Context, tenant, id string) (*Filter, error) { + fltr := new(Filter) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColFlt).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(fltr) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil - }); err != nil { + return decodeErr + }) + if err != nil { return nil, err } - return + return fltr, err } -func (ms *MongoStorage) SetFilterDrv(ctx *context.Context, r *Filter) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColFlt).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetFilterDrv(ctx *context.Context, r *Filter) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColFlt).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -960,8 +912,8 @@ func (ms *MongoStorage) SetFilterDrv(ctx *context.Context, r *Filter) (err error }) } -func (ms *MongoStorage) RemoveFilterDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveFilterDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColFlt).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -970,25 +922,22 @@ func (ms *MongoStorage) RemoveFilterDrv(ctx *context.Context, tenant, id string) }) } -func (ms *MongoStorage) GetRouteProfileDrv(ctx *context.Context, tenant, id string) (r *RouteProfile, err error) { - r = new(RouteProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColRts).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetRouteProfileDrv(ctx *context.Context, tenant, id string) (*RouteProfile, error) { + routeProfile := new(RouteProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColRts).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(routeProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return routeProfile, err } -func (ms *MongoStorage) SetRouteProfileDrv(ctx *context.Context, r *RouteProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColRts).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetRouteProfileDrv(ctx *context.Context, r *RouteProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColRts).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -996,8 +945,8 @@ func (ms *MongoStorage) SetRouteProfileDrv(ctx *context.Context, r *RouteProfile }) } -func (ms *MongoStorage) RemoveRouteProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveRouteProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColRts).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1006,25 +955,22 @@ func (ms *MongoStorage) RemoveRouteProfileDrv(ctx *context.Context, tenant, id s }) } -func (ms *MongoStorage) GetAttributeProfileDrv(ctx *context.Context, tenant, id string) (r *AttributeProfile, err error) { - r = new(AttributeProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColAttr).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetAttributeProfileDrv(ctx *context.Context, tenant, id string) (*AttributeProfile, error) { + attrProfile := new(AttributeProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColAttr).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(attrProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return attrProfile, err } -func (ms *MongoStorage) SetAttributeProfileDrv(ctx *context.Context, r *AttributeProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColAttr).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetAttributeProfileDrv(ctx *context.Context, r *AttributeProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColAttr).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -1032,8 +978,8 @@ func (ms *MongoStorage) SetAttributeProfileDrv(ctx *context.Context, r *Attribut }) } -func (ms *MongoStorage) RemoveAttributeProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveAttributeProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColAttr).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1042,25 +988,22 @@ func (ms *MongoStorage) RemoveAttributeProfileDrv(ctx *context.Context, tenant, }) } -func (ms *MongoStorage) GetChargerProfileDrv(ctx *context.Context, tenant, id string) (r *ChargerProfile, err error) { - r = new(ChargerProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColCpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetChargerProfileDrv(ctx *context.Context, tenant, id string) (*ChargerProfile, error) { + chargerProfile := new(ChargerProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColCpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(chargerProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + return chargerProfile, err } -func (ms *MongoStorage) SetChargerProfileDrv(ctx *context.Context, r *ChargerProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColCpp).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetChargerProfileDrv(ctx *context.Context, r *ChargerProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColCpp).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -1068,8 +1011,8 @@ func (ms *MongoStorage) SetChargerProfileDrv(ctx *context.Context, r *ChargerPro }) } -func (ms *MongoStorage) RemoveChargerProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveChargerProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColCpp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1078,25 +1021,22 @@ func (ms *MongoStorage) RemoveChargerProfileDrv(ctx *context.Context, tenant, id }) } -func (ms *MongoStorage) GetDispatcherProfileDrv(ctx *context.Context, tenant, id string) (r *DispatcherProfile, err error) { - r = new(DispatcherProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColDpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrDSPProfileNotFound - } - return err +func (ms *MongoStorage) GetDispatcherProfileDrv(ctx *context.Context, tenant, id string) (*DispatcherProfile, error) { + dspProfile := new(DispatcherProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColDpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(dspProfile) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrDSPProfileNotFound } - return nil + return decodeErr }) - return + return dspProfile, err } -func (ms *MongoStorage) SetDispatcherProfileDrv(ctx *context.Context, r *DispatcherProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColDpp).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetDispatcherProfileDrv(ctx *context.Context, r *DispatcherProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColDpp).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -1104,8 +1044,8 @@ func (ms *MongoStorage) SetDispatcherProfileDrv(ctx *context.Context, r *Dispatc }) } -func (ms *MongoStorage) RemoveDispatcherProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveDispatcherProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColDpp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1114,25 +1054,22 @@ func (ms *MongoStorage) RemoveDispatcherProfileDrv(ctx *context.Context, tenant, }) } -func (ms *MongoStorage) GetDispatcherHostDrv(ctx *context.Context, tenant, id string) (r *DispatcherHost, err error) { - r = new(DispatcherHost) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColDph).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(r); err != nil { - r = nil - if err == mongo.ErrNoDocuments { - return utils.ErrDSPHostNotFound - } - return err +func (ms *MongoStorage) GetDispatcherHostDrv(ctx *context.Context, tenant, id string) (*DispatcherHost, error) { + dspHost := new(DispatcherHost) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColDph).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(dspHost) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrDSPHostNotFound } - return nil + return decodeErr }) - return + return dspHost, err } -func (ms *MongoStorage) SetDispatcherHostDrv(ctx *context.Context, r *DispatcherHost) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColDph).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, +func (ms *MongoStorage) SetDispatcherHostDrv(ctx *context.Context, r *DispatcherHost) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColDph).UpdateOne(sctx, bson.M{"tenant": r.Tenant, "id": r.ID}, bson.M{"$set": r}, options.Update().SetUpsert(true), ) @@ -1140,8 +1077,8 @@ func (ms *MongoStorage) SetDispatcherHostDrv(ctx *context.Context, r *Dispatcher }) } -func (ms *MongoStorage) RemoveDispatcherHostDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveDispatcherHostDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColDph).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1150,59 +1087,56 @@ func (ms *MongoStorage) RemoveDispatcherHostDrv(ctx *context.Context, tenant, id }) } -func (ms *MongoStorage) GetItemLoadIDsDrv(ctx *context.Context, itemIDPrefix string) (loadIDs map[string]int64, err error) { +func (ms *MongoStorage) GetItemLoadIDsDrv(ctx *context.Context, itemIDPrefix string) (map[string]int64, error) { fop := options.FindOne() if itemIDPrefix != "" { fop.SetProjection(bson.M{itemIDPrefix: 1, "_id": 0}) } else { fop.SetProjection(bson.M{"_id": 0}) } - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColLID).FindOne(sctx, bson.D{}, fop) - if err := cur.Decode(&loadIDs); err != nil { - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err + loadIDs := make(map[string]int64) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColLID).FindOne(sctx, bson.D{}, fop) + decodeErr := sr.Decode(&loadIDs) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil - }); err != nil { + return decodeErr + }) + if err != nil { return nil, err } if len(loadIDs) == 0 { return nil, utils.ErrNotFound } - return + return loadIDs, nil } -func (ms *MongoStorage) SetLoadIDsDrv(ctx *context.Context, loadIDs map[string]int64) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColLID).UpdateOne(sctx, bson.D{}, bson.M{"$set": loadIDs}, +func (ms *MongoStorage) SetLoadIDsDrv(ctx *context.Context, loadIDs map[string]int64) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColLID).UpdateOne(sctx, bson.D{}, bson.M{"$set": loadIDs}, options.Update().SetUpsert(true), ) return err }) } -func (ms *MongoStorage) RemoveLoadIDsDrv() (err error) { - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColLID).DeleteMany(sctx, bson.M{}) +func (ms *MongoStorage) RemoveLoadIDsDrv() error { + return ms.query(context.TODO(), func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColLID).DeleteMany(sctx, bson.M{}) return err }) } -func (ms *MongoStorage) GetRateProfileDrv(ctx *context.Context, tenant, id string) (rpp *utils.RateProfile, err error) { +func (ms *MongoStorage) GetRateProfileDrv(ctx *context.Context, tenant, id string) (*utils.RateProfile, error) { mapRP := make(map[string]any) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColRpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(mapRP); err != nil { - rpp = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColRpp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(mapRP) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) if err != nil { return nil, err @@ -1276,10 +1210,10 @@ func newAggregateStages(profileID, tenant, prefix string) (match, query bson.D) return } -func (ms *MongoStorage) SetRateProfileDrv(ctx *context.Context, rpp *utils.RateProfile, optOverwrite bool) (err error) { +func (ms *MongoStorage) SetRateProfileDrv(ctx *context.Context, rpp *utils.RateProfile, optOverwrite bool) error { rpMap, err := rpp.AsDataDBMap(ms.ms) if err != nil { - return + return err } return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { if optOverwrite { @@ -1317,25 +1251,25 @@ func (ms *MongoStorage) RemoveRateProfileDrv(ctx *context.Context, tenant, id st }) } -func (ms *MongoStorage) GetActionProfileDrv(ctx *context.Context, tenant, id string) (ap *ActionProfile, err error) { - ap = new(ActionProfile) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColApp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(ap); err != nil { - ap = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetActionProfileDrv(ctx *context.Context, tenant, id string) (*ActionProfile, error) { + ap := new(ActionProfile) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColApp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(ap) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + if err != nil { + return nil, err + } + return ap, nil } -func (ms *MongoStorage) SetActionProfileDrv(ctx *context.Context, ap *ActionProfile) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColApp).UpdateOne(sctx, bson.M{"tenant": ap.Tenant, "id": ap.ID}, +func (ms *MongoStorage) SetActionProfileDrv(ctx *context.Context, ap *ActionProfile) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColApp).UpdateOne(sctx, bson.M{"tenant": ap.Tenant, "id": ap.ID}, bson.M{"$set": ap}, options.Update().SetUpsert(true), ) @@ -1343,8 +1277,8 @@ func (ms *MongoStorage) SetActionProfileDrv(ctx *context.Context, ap *ActionProf }) } -func (ms *MongoStorage) RemoveActionProfileDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveActionProfileDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColApp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1356,7 +1290,7 @@ func (ms *MongoStorage) RemoveActionProfileDrv(ctx *context.Context, tenant, id // GetIndexesDrv retrieves Indexes from dataDB // the key is the tenant of the item or in case of context dependent profiles is a concatenatedKey between tenant and context // id is used as a concatenated key in case of filterIndexes the id will be filterType:fieldName:fieldVal -func (ms *MongoStorage) GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error) { +func (ms *MongoStorage) GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (map[string]utils.StringSet, error) { type result struct { Key string Value []string @@ -1373,19 +1307,25 @@ func (ms *MongoStorage) GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, for _, character := range []string{".", "*"} { dbKey = strings.Replace(dbKey, character, `\`+character, strings.Count(dbKey, character)) } - //inside bson.RegEx add carrot to match the prefix (optimization) - q = bson.M{"key": bsonx.Regex("^"+dbKey, utils.EmptyString)} + // For optimization, use a caret (^) in the regex pattern. + q = bson.M{"key": primitive.Regex{Pattern: "^" + dbKey}} } - indexes = make(map[string]utils.StringSet) - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(ColIndx).Find(sctx, q) - if err != nil { - return err + indexes := make(map[string]utils.StringSet) + err := ms.query(ctx, func(sctx mongo.SessionContext) (qryErr error) { + cur, qryErr := ms.getCol(ColIndx).Find(sctx, q) + if qryErr != nil { + return qryErr } + defer func() { + closeErr := cur.Close(sctx) + if closeErr != nil && qryErr == nil { + qryErr = closeErr + } + }() for cur.Next(sctx) { var elem result - if err := cur.Decode(&elem); err != nil { - return err + if qryErr := cur.Decode(&elem); qryErr != nil { + return qryErr } if len(elem.Value) == 0 { continue @@ -1393,8 +1333,9 @@ func (ms *MongoStorage) GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, indexKey := strings.TrimPrefix(elem.Key, originKey+utils.ConcatenatedKeySep) indexes[indexKey] = utils.NewStringSet(elem.Value) } - return cur.Close(sctx) - }); err != nil { + return cur.Err() + }) + if err != nil { return nil, err } if len(indexes) == 0 { @@ -1406,7 +1347,7 @@ func (ms *MongoStorage) GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, // SetIndexesDrv stores Indexes into DataDB // the key is the tenant of the item or in case of context dependent profiles is a concatenatedKey between tenant and context func (ms *MongoStorage) SetIndexesDrv(ctx *context.Context, idxItmType, tntCtx string, - indexes map[string]utils.StringSet, commit bool, transactionID string) (err error) { + indexes map[string]utils.StringSet, commit bool, transactionID string) error { originKey := utils.CacheInstanceToPrefix[idxItmType] + tntCtx dbKey := originKey if transactionID != utils.EmptyString { @@ -1415,46 +1356,47 @@ func (ms *MongoStorage) SetIndexesDrv(ctx *context.Context, idxItmType, tntCtx s if commit && transactionID != utils.EmptyString { regexKey := dbKey for _, character := range []string{".", "*"} { - regexKey = strings.Replace(regexKey, character, `\`+character, strings.Count(regexKey, character)) + regexKey = strings.ReplaceAll(regexKey, character, `\`+character) } - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - var result []string - result, err = ms.getField3(sctx, ColIndx, regexKey, "key") - if err != nil { - return + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + result, qryErr := ms.getAllIndexKeys(sctx, regexKey) + if qryErr != nil { + return qryErr } for _, key := range result { idxKey := strings.TrimPrefix(key, dbKey) - if _, err = ms.getCol(ColIndx).DeleteOne(sctx, - bson.M{"key": originKey + idxKey}); err != nil { //ensure we do not have dup - return err + if _, qryErr = ms.getCol(ColIndx).DeleteOne(sctx, + bson.M{"key": originKey + idxKey}); qryErr != nil { //ensure we do not have dup + return qryErr } - if _, err = ms.getCol(ColIndx).UpdateOne(sctx, bson.M{"key": key}, + if _, qryErr = ms.getCol(ColIndx).UpdateOne(sctx, bson.M{"key": key}, bson.M{"$set": bson.M{"key": originKey + idxKey}}, // only update the key - ); err != nil { - return err + ); qryErr != nil { + return qryErr } } return nil - }); err != nil { + }) + if err != nil { return err } } var lastErr error for idxKey, itmMp := range indexes { - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { + err := ms.query(ctx, func(sctx mongo.SessionContext) (qryErr error) { idxDbkey := utils.ConcatenatedKey(dbKey, idxKey) if len(itmMp) == 0 { // remove from DB if we set it with empty indexes - _, err = ms.getCol(ColIndx).DeleteOne(sctx, + _, qryErr = ms.getCol(ColIndx).DeleteOne(sctx, bson.M{"key": idxDbkey}) } else { - _, err = ms.getCol(ColIndx).UpdateOne(sctx, bson.M{"key": idxDbkey}, + _, qryErr = ms.getCol(ColIndx).UpdateOne(sctx, bson.M{"key": idxDbkey}, bson.M{"$set": bson.M{"key": idxDbkey, "value": itmMp.AsSlice()}}, options.Update().SetUpsert(true), ) } - return err - }); err != nil { + return qryErr + }) + if err != nil { lastErr = err } } @@ -1462,9 +1404,9 @@ func (ms *MongoStorage) SetIndexesDrv(ctx *context.Context, idxItmType, tntCtx s } // RemoveIndexesDrv removes the indexes -func (ms *MongoStorage) RemoveIndexesDrv(ctx *context.Context, idxItmType, tntCtx, idxKey string) (err error) { +func (ms *MongoStorage) RemoveIndexesDrv(ctx *context.Context, idxItmType, tntCtx, idxKey string) error { if len(idxKey) != 0 { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColIndx).DeleteOne(sctx, bson.M{"key": utils.ConcatenatedKey(utils.CacheInstanceToPrefix[idxItmType]+tntCtx, idxKey)}) if dr.DeletedCount == 0 { @@ -1475,34 +1417,38 @@ func (ms *MongoStorage) RemoveIndexesDrv(ctx *context.Context, idxItmType, tntCt } regexKey := utils.CacheInstanceToPrefix[idxItmType] + tntCtx for _, character := range []string{".", "*"} { - regexKey = strings.Replace(regexKey, character, `\`+character, strings.Count(regexKey, character)) + regexKey = strings.ReplaceAll(regexKey, character, `\`+character) } - //inside bson.RegEx add carrot to match the prefix (optimization) - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColIndx).DeleteMany(sctx, bson.M{"key": bsonx.Regex("^"+regexKey, utils.EmptyString)}) + // For optimization, use a caret (^) in the regex pattern. + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColIndx).DeleteMany(sctx, bson.M{ + "key": primitive.Regex{ + Pattern: "^" + regexKey, + }, + }) return err }) } -func (ms *MongoStorage) GetAccountDrv(ctx *context.Context, tenant, id string) (ap *utils.Account, err error) { - ap = new(utils.Account) - err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - cur := ms.getCol(ColAnp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) - if err := cur.Decode(ap); err != nil { - ap = nil - if err == mongo.ErrNoDocuments { - return utils.ErrNotFound - } - return err +func (ms *MongoStorage) GetAccountDrv(ctx *context.Context, tenant, id string) (*utils.Account, error) { + ap := new(utils.Account) + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + sr := ms.getCol(ColAnp).FindOne(sctx, bson.M{"tenant": tenant, "id": id}) + decodeErr := sr.Decode(ap) + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return utils.ErrNotFound } - return nil + return decodeErr }) - return + if err != nil { + return nil, err + } + return ap, nil } -func (ms *MongoStorage) SetAccountDrv(ctx *context.Context, ap *utils.Account) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColAnp).UpdateOne(sctx, bson.M{"tenant": ap.Tenant, "id": ap.ID}, +func (ms *MongoStorage) SetAccountDrv(ctx *context.Context, ap *utils.Account) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColAnp).UpdateOne(sctx, bson.M{"tenant": ap.Tenant, "id": ap.ID}, bson.M{"$set": ap}, options.Update().SetUpsert(true), ) @@ -1510,8 +1456,8 @@ func (ms *MongoStorage) SetAccountDrv(ctx *context.Context, ap *utils.Account) ( }) } -func (ms *MongoStorage) RemoveAccountDrv(ctx *context.Context, tenant, id string) (err error) { - return ms.query(ctx, func(sctx mongo.SessionContext) (err error) { +func (ms *MongoStorage) RemoveAccountDrv(ctx *context.Context, tenant, id string) error { + return ms.query(ctx, func(sctx mongo.SessionContext) error { dr, err := ms.getCol(ColAnp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id}) if dr.DeletedCount == 0 { return utils.ErrNotFound @@ -1520,39 +1466,39 @@ func (ms *MongoStorage) RemoveAccountDrv(ctx *context.Context, tenant, id string }) } -func (ms *MongoStorage) GetConfigSectionsDrv(ctx *context.Context, nodeID string, sectionIDs []string) (sectionMap map[string][]byte, err error) { - sectionMap = make(map[string][]byte) +func (ms *MongoStorage) GetConfigSectionsDrv(ctx *context.Context, nodeID string, sectionIDs []string) (map[string][]byte, error) { + sectionMap := make(map[string][]byte) for _, sectionID := range sectionIDs { - if err = ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { + err := ms.query(ctx, func(sctx mongo.SessionContext) error { cur := ms.getCol(ColCfg).FindOne(sctx, bson.M{ "nodeID": nodeID, "section": sectionID, }, options.FindOne().SetProjection(bson.M{"cfgData": 1, "_id": 0})) cfgMap := make(map[string][]byte) - if err = cur.Decode(&cfgMap); err != nil { - if err == mongo.ErrNoDocuments { - err = nil - return + decodeErr := cur.Decode(&cfgMap) + if decodeErr != nil { + if errors.Is(decodeErr, mongo.ErrNoDocuments) { + return nil } - return + return decodeErr } sectionMap[sectionID] = cfgMap["cfgData"] - return - }); err != nil { - return + return nil + }) + if err != nil { + return nil, err } } if len(sectionMap) == 0 { - err = utils.ErrNotFound - return + return nil, utils.ErrNotFound } - return + return sectionMap, nil } -func (ms *MongoStorage) SetConfigSectionsDrv(ctx *context.Context, nodeID string, sectionsData map[string][]byte) (err error) { +func (ms *MongoStorage) SetConfigSectionsDrv(ctx *context.Context, nodeID string, sectionsData map[string][]byte) error { for sectionID, sectionData := range sectionsData { - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColCfg).UpdateOne(sctx, bson.M{ + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + _, qryErr := ms.getCol(ColCfg).UpdateOne(sctx, bson.M{ "nodeID": nodeID, "section": sectionID, }, bson.M{"$set": bson.M{ @@ -1561,25 +1507,27 @@ func (ms *MongoStorage) SetConfigSectionsDrv(ctx *context.Context, nodeID string "cfgData": sectionData}}, options.Update().SetUpsert(true), ) + return qryErr + }) + if err != nil { return err - }); err != nil { - return } } - return + return nil } -func (ms *MongoStorage) RemoveConfigSectionsDrv(ctx *context.Context, nodeID string, sectionIDs []string) (err error) { +func (ms *MongoStorage) RemoveConfigSectionsDrv(ctx *context.Context, nodeID string, sectionIDs []string) error { for _, sectionID := range sectionIDs { - if err = ms.query(ctx, func(sctx mongo.SessionContext) (err error) { - _, err = ms.getCol(ColCfg).DeleteOne(sctx, bson.M{ + err := ms.query(ctx, func(sctx mongo.SessionContext) error { + _, err := ms.getCol(ColCfg).DeleteOne(sctx, bson.M{ "nodeID": nodeID, "section": sectionID, }) return err - }); err != nil { - return + }) + if err != nil { + return err } } - return + return nil } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index 24bace86f..a0beb80de 100644 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -20,7 +20,6 @@ package engine import ( "fmt" - "regexp" "strings" "time" @@ -31,765 +30,8 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/x/bsonx" ) -func (ms *MongoStorage) GetTpIds(colName string) (tpids []string, err error) { - getTpIDs := func(ctx mongo.SessionContext, col string, tpMap utils.StringSet) (utils.StringSet, error) { - if strings.HasPrefix(col, "tp_") { - result, err := ms.getCol(col).Distinct(ctx, "tpid", bson.D{}) - if err != nil { - return tpMap, err - } - for _, tpid := range result { - tpMap.Add(tpid.(string)) - } - } - return tpMap, nil - } - tpidMap := make(utils.StringSet) - - if colName == "" { - if err := ms.query(context.TODO(), func(sctx mongo.SessionContext) error { - col, err := ms.DB().ListCollections(sctx, bson.D{}, options.ListCollections().SetNameOnly(true)) - if err != nil { - return err - } - for col.Next(sctx) { - var elem struct{ Name string } - if err := col.Decode(&elem); err != nil { - return err - } - if tpidMap, err = getTpIDs(sctx, elem.Name, tpidMap); err != nil { - return err - } - } - return col.Close(sctx) - }); err != nil { - return nil, err - } - } else { - if err := ms.query(context.TODO(), func(sctx mongo.SessionContext) error { - tpidMap, err = getTpIDs(sctx, colName, tpidMap) - return err - }); err != nil { - return nil, err - } - } - tpids = tpidMap.AsSlice() - return tpids, nil -} - -func (ms *MongoStorage) GetTpTableIds(tpid, table string, distinct []string, - filter map[string]string, pag *utils.PaginatorWithSearch) ([]string, error) { - findMap := bson.M{} - if tpid != "" { - findMap["tpid"] = tpid - } - for k, v := range filter { - if k != "" && v != "" { - findMap[k] = v - } - } - - fop := options.Find() - if pag != nil { - if pag.Search != "" { - var searchItems []bson.M - for _, d := range distinct { - searchItems = append(searchItems, bson.M{d: bsonx.Regex(".*"+regexp.QuoteMeta(pag.Search)+".*", "")}) - } - // findMap["$and"] = []bson.M{{"$or": searchItems}} //before - findMap["$or"] = searchItems // after - } - if pag.Paginator != nil { - if pag.Limit != nil { - fop = fop.SetLimit(int64(*pag.Limit)) - } - if pag.Offset != nil { - fop = fop.SetSkip(int64(*pag.Offset)) - } - } - } - - selectors := bson.M{"_id": 0} - for i, d := range distinct { - if d == "tag" { // convert the tag used in SQL into id used here - distinct[i] = "id" - } - selectors[distinct[i]] = 1 - } - fop.SetProjection(selectors) - - distinctIds := make(utils.StringSet) - if err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(table).Find(sctx, findMap, fop) - if err != nil { - return err - } - for cur.Next(sctx) { - var elem bson.D - err := cur.Decode(&elem) - if err != nil { - return err - } - item := elem.Map() - - var id string - last := len(distinct) - 1 - for i, d := range distinct { - if distinctValue, ok := item[d]; ok { - id += distinctValue.(string) - } - if i < last { - id += utils.ConcatenatedKeySep - } - } - distinctIds.Add(id) - } - return cur.Close(sctx) - }); err != nil { - return nil, err - } - return distinctIds.AsSlice(), nil -} - -func (ms *MongoStorage) GetTPResources(tpid, tenant, id string) ([]*utils.TPResourceProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPResourceProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPResources).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var el utils.TPResourceProfile - err := cur.Decode(&el) - if err != nil { - return err - } - results = append(results, &el) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) GetTPStats(tpid, tenant, id string) ([]*utils.TPStatProfile, error) { - filter := bson.M{ - "tpid": tpid, - } - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPStatProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPStats).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var el utils.TPStatProfile - err := cur.Decode(&el) - if err != nil { - return err - } - results = append(results, &el) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) RemTpData(table, tpid string, args map[string]string) error { - if len(table) == 0 { // Remove tpid out of all tables - return ms.query(context.TODO(), func(sctx mongo.SessionContext) error { - col, err := ms.DB().ListCollections(sctx, bson.D{}, options.ListCollections().SetNameOnly(true)) - if err != nil { - return err - } - for col.Next(sctx) { - var elem struct{ Name string } - if err := col.Decode(&elem); err != nil { - return err - } - if strings.HasPrefix(elem.Name, "tp_") { - _, err = ms.getCol(elem.Name).DeleteMany(sctx, bson.M{"tpid": tpid}) - if err != nil { - return err - } - } - } - return col.Close(sctx) - }) - } - // Remove from a single table - if args == nil { - args = make(map[string]string) - } - - if _, has := args["tag"]; has { // API uses tag to be compatible with SQL models, fix it here - args["id"] = args["tag"] - delete(args, "tag") - } - if tpid != "" { - args["tpid"] = tpid - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - dr, err := ms.getCol(table).DeleteOne(sctx, args) - if dr.DeletedCount == 0 { - return utils.ErrNotFound - } - return err - }) -} - -func (ms *MongoStorage) SetTPResources(tpRLs []*utils.TPResourceProfile) (err error) { - if len(tpRLs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpRLs { - _, err = ms.getCol(utils.TBLTPResources).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, options.Update().SetUpsert(true)) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) SetTPRStats(tps []*utils.TPStatProfile) (err error) { - if len(tps) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tps { - _, err = ms.getCol(utils.TBLTPStats).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, options.Update().SetUpsert(true)) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) SetTPStats(tpSTs []*utils.TPStatProfile) (err error) { - if len(tpSTs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpSTs { - _, err = ms.getCol(utils.TBLTPStats).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPThresholds(tpid, tenant, id string) ([]*utils.TPThresholdProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPThresholdProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPThresholds).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPThresholdProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPThresholds(tpTHs []*utils.TPThresholdProfile) (err error) { - if len(tpTHs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpTHs { - _, err = ms.getCol(utils.TBLTPThresholds).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPFilters(tpid, tenant, id string) ([]*utils.TPFilterProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - results := []*utils.TPFilterProfile{} - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPFilters).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPFilterProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPFilters(tpTHs []*utils.TPFilterProfile) (err error) { - if len(tpTHs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpTHs { - _, err = ms.getCol(utils.TBLTPFilters).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPRoutes(tpid, tenant, id string) ([]*utils.TPRouteProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPRouteProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPRoutes).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPRouteProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPRoutes(tpRoutes []*utils.TPRouteProfile) (err error) { - if len(tpRoutes) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpRoutes { - _, err = ms.getCol(utils.TBLTPRoutes).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPAttributes(tpid, tenant, id string) ([]*utils.TPAttributeProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPAttributeProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPAttributes).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPAttributeProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPAttributes(tpRoutes []*utils.TPAttributeProfile) (err error) { - if len(tpRoutes) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpRoutes { - _, err = ms.getCol(utils.TBLTPAttributes).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPChargers(tpid, tenant, id string) ([]*utils.TPChargerProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPChargerProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPChargers).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPChargerProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPChargers(tpCPP []*utils.TPChargerProfile) (err error) { - if len(tpCPP) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpCPP { - _, err = ms.getCol(utils.TBLTPChargers).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPDispatcherProfiles(tpid, tenant, id string) ([]*utils.TPDispatcherProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPDispatcherProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPDispatchers).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPDispatcherProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPDispatcherProfiles(tpDPPs []*utils.TPDispatcherProfile) (err error) { - if len(tpDPPs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpDPPs { - _, err = ms.getCol(utils.TBLTPDispatchers).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPDispatcherHosts(tpid, tenant, id string) ([]*utils.TPDispatcherHost, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPDispatcherHost - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPDispatcherHosts).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPDispatcherHost - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPDispatcherHosts(tpDPPs []*utils.TPDispatcherHost) (err error) { - if len(tpDPPs) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpDPPs { - _, err = ms.getCol(utils.TBLTPDispatcherHosts).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPRateProfiles(tpid, tenant, id string) ([]*utils.TPRateProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPRateProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPRateProfiles).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPRateProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPRateProfiles(tpDPPs []*utils.TPRateProfile) (err error) { - if len(tpDPPs) == 0 { - return - } - - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpDPPs { - _, err = ms.getCol(utils.TBLTPRateProfiles).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) GetTPActionProfiles(tpid, tenant, id string) ([]*utils.TPActionProfile, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPActionProfile - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPActionProfiles).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPActionProfile - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) GetTPAccounts(tpid, tenant, id string) ([]*utils.TPAccount, error) { - filter := bson.M{"tpid": tpid} - if id != "" { - filter["id"] = id - } - if tenant != "" { - filter["tenant"] = tenant - } - var results []*utils.TPAccount - err := ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - cur, err := ms.getCol(utils.TBLTPAccounts).Find(sctx, filter) - if err != nil { - return err - } - for cur.Next(sctx) { - var tp utils.TPAccount - err := cur.Decode(&tp) - if err != nil { - return err - } - results = append(results, &tp) - } - if len(results) == 0 { - return utils.ErrNotFound - } - return cur.Close(sctx) - }) - return results, err -} - -func (ms *MongoStorage) SetTPActionProfiles(tpAps []*utils.TPActionProfile) (err error) { - if len(tpAps) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpAps { - _, err = ms.getCol(utils.TBLTPActionProfiles).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - -func (ms *MongoStorage) SetTPAccounts(tpAps []*utils.TPAccount) (err error) { - if len(tpAps) == 0 { - return - } - return ms.query(context.TODO(), func(sctx mongo.SessionContext) (err error) { - for _, tp := range tpAps { - _, err = ms.getCol(utils.TBLTPAccounts).UpdateOne(sctx, bson.M{"tpid": tp.TPid, "id": tp.ID}, - bson.M{"$set": tp}, - options.Update().SetUpsert(true), - ) - if err != nil { - return err - } - } - return nil - }) -} - func (ms *MongoStorage) GetVersions(itm string) (vrs Versions, err error) { fop := options.FindOne() if itm != "" { @@ -864,7 +106,7 @@ func (ms *MongoStorage) GetStorageType() string { func (ms *MongoStorage) SetCDR(cdr *utils.CGREvent, allowUpdate bool) error { if val, has := cdr.Event[utils.OrderID]; has && val == 0 { - cdr.Event[utils.OrderID] = ms.cnter.Next() + cdr.Event[utils.OrderID] = ms.counter.Next() } cdrTable := &CDR{ Tenant: cdr.Tenant, @@ -998,14 +240,18 @@ func getQueryType(ruleType string, not bool, values []string) (msQuery string, v if not { msQuery = "$nin" } - regex := make([]bsonx.Val, 0, len(values)) + regex := make([]primitive.Regex, 0, len(values)) if ruleType == utils.MetaPrefix || ruleType == utils.MetaNotPrefix { for _, val := range values { - regex = append(regex, bsonx.Regex("/^"+val+"/", utils.EmptyString)) + regex = append(regex, primitive.Regex{ + Pattern: "/^" + val + "/", + }) } } else { for _, val := range values { - regex = append(regex, bsonx.Regex("/"+val+"$/", utils.EmptyString)) + regex = append(regex, primitive.Regex{ + Pattern: "/" + val + "$/", + }) } } valChanged = regex diff --git a/engine/storage_utils.go b/engine/storage_utils.go index 0c02aab42..9f966c1ab 100644 --- a/engine/storage_utils.go +++ b/engine/storage_utils.go @@ -20,6 +20,9 @@ package engine import ( "fmt" + "net" + "net/url" + "path" "strconv" "strings" @@ -79,3 +82,21 @@ func NewStorDBConn(dbType, host, port, name, user, pass, marshaler string, } return } + +func buildURL(scheme, host, port, db, user, pass string) (*url.URL, error) { + u, err := url.Parse("//" + host) + if err != nil { + return nil, err + } + if port != "0" { + u.Host = net.JoinHostPort(u.Host, port) + } + if user != "" && pass != "" { + u.User = url.UserPassword(user, pass) + } + if db != "" { + u.Path = path.Join(u.Path, db) + } + u.Scheme = scheme + return u, nil +} diff --git a/go.mod b/go.mod index 23a1548eb..5c10f7fbf 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/peterh/liner v1.2.2 github.com/rabbitmq/amqp091-go v1.5.0 github.com/segmentio/kafka-go v0.4.32 - go.mongodb.org/mongo-driver v1.11.0 + go.mongodb.org/mongo-driver v1.13.0 golang.org/x/crypto v0.13.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/net v0.15.0 @@ -87,7 +87,6 @@ require ( github.com/nats-io/nats-server/v2 v2.10.1 github.com/nats-io/nkeys v0.4.5 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.12.2 github.com/rivo/uniseg v0.2.0 // indirect github.com/steveyen/gtreap v0.1.0 // indirect @@ -126,8 +125,8 @@ require ( github.com/prometheus/common v0.35.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.1 // indirect - github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect golang.org/x/time v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index 97f953ccb..02c1ecd86 100644 --- a/go.sum +++ b/go.sum @@ -413,11 +413,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -563,8 +561,6 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= @@ -575,10 +571,10 @@ github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw= github.com/xdg/scram v1.0.5/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -594,12 +590,13 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= -go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY= +go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -678,6 +675,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -731,6 +729,7 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -767,6 +766,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -848,6 +848,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -862,6 +863,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -927,6 +930,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1139,9 +1143,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 h1:dbuHpmKjkDzSOMKAWl10QNlgaZUd3V1q99xc81tt2Kc= gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.3.4 h1:/KoBMgsUHC3bExsekDcmNYaBnfH2WNeFuXqqrqMc98Q= gorm.io/driver/mysql v1.3.4/go.mod h1:s4Tq0KmD0yhPGHbZEwg1VPlH0vT/GBHJZorPzhcxBUE= gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ=