package repository import ( "context" "fmt" "log" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo" ) type AccountRepositoryDeps struct { Logger *zap.Logger MongoDB *mongo.Collection } type AccountRepository struct { logger *zap.Logger mongoDB *mongo.Collection } func NewAccountRepository(deps *AccountRepositoryDeps) *AccountRepository { if deps == nil { log.Panicln("deps is nil on ") } if deps.Logger == nil { log.Panicln("logger is nil on ") } if deps.MongoDB == nil { log.Panicln("repository is nil on ") } return &AccountRepository{ logger: deps.Logger, mongoDB: deps.MongoDB, } } func (receiver *AccountRepository) FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) { filter := bson.M{ fields.Account.UserID: id, fields.Account.Deleted: false, } account, err := mongoWrapper.FindOne[models.Account](ctx, &mongoWrapper.RequestSettings{ Driver: receiver.mongoDB, Filter: filter, }) if err != nil { receiver.logger.Error("failed to find account by userID on of ", zap.String("id", id), zap.Error(err), ) findError := errors.New( fmt.Errorf("failed to find account with <%s> on of : %w", id, err), errors.ErrInternalError, ) if err == mongo.ErrNoDocuments { findError.SetType(errors.ErrNotFound) } return nil, findError } return account, nil } func (receiver *AccountRepository) FindMany(ctx context.Context, page, limit int64) ([]models.Account, errors.Error) { filter := bson.M{fields.Account.Deleted: false} findOptions := options.Find() skip := (page - 1) * limit findOptions.SetSkip(skip) findOptions.SetLimit(limit) accounts, err := mongoWrapper.Find[models.Account](ctx, &mongoWrapper.RequestSettings{ Driver: receiver.mongoDB, Options: findOptions, Filter: filter, }) if err != nil { receiver.logger.Error("failed to find many accounts on of ", zap.Int64("page", page), zap.Int64("limit", limit), zap.Int64("skip", skip), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to find many accounts on of : %w", err), errors.ErrInternalError, ) } return accounts, nil } func (receiver *AccountRepository) Insert(ctx context.Context, account *models.Account) (*models.Account, errors.Error) { account.CreatedAt = time.Now() account.UpdatedAt = time.Now() account.Deleted = false result, err := receiver.mongoDB.InsertOne(ctx, account) if err != nil { receiver.logger.Error("failed to insert account on of ", zap.Any("account", account), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to insert account on of : %w", err), errors.ErrInternalError, ) } insertedID := result.InsertedID.(primitive.ObjectID).Hex() account.ID = insertedID return account, nil } func (receiver *AccountRepository) Remove(ctx context.Context, id string) (*models.Account, errors.Error) { account := models.Account{} update := bson.M{"$set": bson.M{ fields.Account.Deleted: true, fields.Account.DeletedAt: time.Now(), }} filter := bson.M{ fields.Account.UserID: id, fields.Account.Deleted: false, } if err := receiver.mongoDB.FindOneAndUpdate(ctx, filter, update).Decode(&account); err != nil { receiver.logger.Error("failed to set 'deleted=true' on of ", zap.String("id", id), zap.Error(err), ) removeErr := errors.New( fmt.Errorf("failed to remove account with <%s> on of : %w", id, err), errors.ErrInternalError, ) if err == mongo.ErrNoDocuments { removeErr.SetType(errors.ErrNotFound) } return nil, removeErr } return &account, nil } func (receiver *AccountRepository) Delete(ctx context.Context, id string) (*models.Account, errors.Error) { account := models.Account{} filter := bson.M{ fields.Account.UserID: id, fields.Account.Deleted: false, } if err := receiver.mongoDB.FindOneAndDelete(ctx, filter).Decode(&account); err != nil { receiver.logger.Error("failed delete account on of ", zap.String("id", id), zap.Error(err), ) removeErr := errors.New( fmt.Errorf("failed to remove account with <%s> on of : %w", id, err), errors.ErrInternalError, ) if err == mongo.ErrNoDocuments { removeErr.SetType(errors.ErrNotFound) } return nil, removeErr } return &account, nil } func (receiver *AccountRepository) CountAll(ctx context.Context) (int64, errors.Error) { count, err := receiver.mongoDB.CountDocuments(ctx, bson.M{fields.Account.Deleted: false}) if err != nil { receiver.logger.Error("failed to count all documents on of ", zap.Error(err), ) return 0, errors.New( fmt.Errorf("failed to count all documents on of : %w", err), errors.ErrInternalError, ) } return count, nil }