package repository import ( "codeword/internal/models" "context" "errors" "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" "time" ) var ( ErrDuplicateCodeword = errors.New("duplicate codeword") ErrPromoCodeNotFound = errors.New("promo code not found") ) type PromoCodeRepository struct { mdb *mongo.Collection } func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository { indexModel := mongo.IndexModel{ Keys: bson.D{ {"codeword", 1}, {"delete", 1}, }, Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}), } _, err := mdb.Indexes().CreateOne(context.Background(), indexModel) if err != nil { panic(err) } return &PromoCodeRepository{mdb: mdb} } func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, promoCode *models.PromoCode) (*models.PromoCode, error) { promoCode.CreatedAt = time.Now() promoCode.ID = primitive.NewObjectID() _, err := r.mdb.InsertOne(ctx, promoCode) if err != nil { if writeErr, ok := err.(mongo.WriteException); ok { for _, writeError := range writeErr.WriteErrors { if writeError.Code == 11000 { return nil, ErrDuplicateCodeword } } } return nil, err } return promoCode, nil } func (r *PromoCodeRepository) EditPromoCode(ctx context.Context, editPromoCode *models.ReqEditPromoCode) (*models.PromoCode, error) { promoCodeID, err := primitive.ObjectIDFromHex(editPromoCode.ID) if err != nil { return nil, err } updateFields := bson.M{} if editPromoCode.Description != nil { updateFields["description"] = *editPromoCode.Description } if editPromoCode.Greetings != nil { updateFields["greetings"] = *editPromoCode.Greetings } if editPromoCode.DueTo != nil { updateFields["dueTo"] = *editPromoCode.DueTo } if editPromoCode.ActivationCount != nil { updateFields["activationCount"] = *editPromoCode.ActivationCount } if editPromoCode.Delete != nil { updateFields["delete"] = *editPromoCode.Delete } if len(updateFields) == 0 { return r.GetPromoCodeByID(ctx, promoCodeID) } update := bson.M{"$set": updateFields} result, err := r.mdb.UpdateOne(ctx, bson.M{"_id": promoCodeID}, update) if err != nil { return nil, err } if result.MatchedCount == 0 { return nil, ErrPromoCodeNotFound } return r.GetPromoCodeByID(ctx, promoCodeID) } func (r *PromoCodeRepository) GetPromoCodeByID(ctx context.Context, promoCodeID primitive.ObjectID) (*models.PromoCode, error) { var promoCode models.PromoCode err := r.mdb.FindOne(ctx, bson.M{"_id": promoCodeID}).Decode(&promoCode) if err != nil { if err == mongo.ErrNoDocuments { return nil, ErrPromoCodeNotFound } return nil, err } return &promoCode, nil }