package repository import ( "context" "fmt" "go.mongodb.org/mongo-driver/bson" "log" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields" "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/dto" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo" ) type HistoryRepositoryDeps struct { Logger *zap.Logger MongoDB *mongo.Collection } type HistoryRepository struct { logger *zap.Logger mongoDB *mongo.Collection } func NewHistoryRepository(deps HistoryRepositoryDeps) *HistoryRepository { if deps.Logger == nil { log.Panicln("logger is nil on ") } if deps.MongoDB == nil { log.Panicln("mongodb is nil on ") } return &HistoryRepository{ logger: deps.Logger, mongoDB: deps.MongoDB, } } func (receiver *HistoryRepository) Insert(ctx context.Context, history *models.History) (*models.History, errors.Error) { result, err := receiver.mongoDB.InsertOne(ctx, history.Sanitize()) if err != nil { receiver.logger.Error("failed to insert history on of ", zap.Any("history", history), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to insert history on of : %w", err), errors.ErrInternalError, ) } insertedID := result.InsertedID.(primitive.ObjectID).Hex() history.ID = insertedID return history, nil } func (receiver *HistoryRepository) FindMany(ctx context.Context, dto *dto.GetHistories) ([]models.History, errors.Error) { findOptions := options.Find() findOptions.SetSkip((dto.Pagination.Page - 1) * dto.Pagination.Limit) findOptions.SetLimit(dto.Pagination.Limit) findOptions.SetSort(bson.D{{ Key: "createdAt", Value: -1, }}) histories, err := mongoWrapper.Find[models.History](ctx, &mongoWrapper.RequestSettings{ Driver: receiver.mongoDB, Options: findOptions, Filter: dto.BSON(), }) if err != nil { receiver.logger.Error("failed to find many histories on of ", zap.Int64("page", dto.Pagination.Page), zap.Int64("limit", dto.Pagination.Limit), zap.Int64("skip", (dto.Pagination.Page-1)*dto.Pagination.Limit), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to find many histories on of : %w", err), errors.ErrInternalError, ) } return histories, nil } func (receiver *HistoryRepository) CountAll(ctx context.Context, dto *dto.GetHistories) (int64, errors.Error) { count, err := receiver.mongoDB.CountDocuments(ctx, dto.BSON()) 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 } // TODO:tests // GetRecentTariffs method for processing a user request with data aggregation with a limit of 100 sorted in descending order func (receiver *HistoryRepository) GetRecentTariffs(ctx context.Context, userID string) ([]string, errors.Error) { var result []struct { ID string `bson:"tariffID"` } filter := bson.D{ {fields.History.UserID, userID}, {fields.History.IsDeleted, false}, } pipeline := mongo.Pipeline{ {{"$match", filter}}, {{"$unwind", "$rawDetails"}}, {{"$match", bson.D{{"rawDetails.Key", "tariffs"}}}}, {{"$unwind", "$rawDetails.Value"}}, {{"$group", bson.D{{"_id", "$rawDetails.Value.Key.id"}}}}, {{"$sort", bson.D{{"createdAt", -1}}}}, // -1 specifies descending order {{"$limit", 100}}, } cursor, err := receiver.mongoDB.Aggregate(ctx, pipeline) if err != nil { receiver.logger.Error("failed to get recent tariffs on of ", zap.String("userId", userID), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to get recent tariffs on of : %w", err), errors.ErrInternalError, ) } if err := cursor.All(ctx, &result); err != nil { receiver.logger.Error("failed to decode recent tariffs on of ", zap.String("userId", userID), zap.Error(err), ) return nil, errors.New( fmt.Errorf("failed to decode recent tariffs on of : %w", err), errors.ErrInternalError, ) } tariffs := make([]string, len(result)) for i, item := range result { tariffs[i] = item.ID } return tariffs, nil }