codeword/internal/repository/promocode_repository.go

188 lines
4.5 KiB
Go
Raw Normal View History

2024-01-11 16:29:53 +00:00
package repository
import (
"codeword/internal/models"
"context"
2024-01-11 18:20:33 +00:00
"errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
2024-01-11 16:29:53 +00:00
"go.mongodb.org/mongo-driver/mongo"
2024-01-11 18:20:33 +00:00
"go.mongodb.org/mongo-driver/mongo/options"
2024-01-11 16:29:53 +00:00
"time"
)
2024-01-11 19:47:54 +00:00
var (
ErrDuplicateCodeword = errors.New("duplicate codeword")
ErrPromoCodeNotFound = errors.New("promo code not found")
)
2024-01-11 18:20:33 +00:00
2024-01-12 11:28:22 +00:00
// структура для горутины чтобы ошибки не пропускать
type countResult struct {
count int64
err error
}
2024-01-11 16:29:53 +00:00
type PromoCodeRepository struct {
mdb *mongo.Collection
}
func NewPromoCodeRepository(mdb *mongo.Collection) *PromoCodeRepository {
2024-01-12 11:28:22 +00:00
// todo заменить паники вроде как в роде не круто их юзать
uniqueIndexModel := mongo.IndexModel{
2024-01-11 18:20:33 +00:00
Keys: bson.D{
2024-01-12 11:28:22 +00:00
{Key: "codeword", Value: 1},
{Key: "delete", Value: 1},
2024-01-11 18:20:33 +00:00
},
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"delete": false}),
}
2024-01-12 11:28:22 +00:00
_, err := mdb.Indexes().CreateOne(context.Background(), uniqueIndexModel)
if err != nil {
panic(err)
}
textIndexModel := mongo.IndexModel{
Keys: bson.D{
{Key: "codeword", Value: "text"},
{Key: "description", Value: "text"},
{Key: "greetings", Value: "text"},
},
Options: options.Index().SetName("TextIndex"),
}
_, err = mdb.Indexes().CreateOne(context.Background(), textIndexModel)
2024-01-11 18:20:33 +00:00
if err != nil {
panic(err)
}
2024-01-11 16:29:53 +00:00
return &PromoCodeRepository{mdb: mdb}
}
2024-01-12 11:28:22 +00:00
func (r *PromoCodeRepository) CreatePromoCode(ctx context.Context, req *models.PromoCode) (*models.PromoCode, error) {
req.CreatedAt = time.Now()
req.ID = primitive.NewObjectID()
2024-01-11 18:20:33 +00:00
2024-01-12 11:28:22 +00:00
_, err := r.mdb.InsertOne(ctx, req)
2024-01-11 16:29:53 +00:00
if err != nil {
2024-01-11 18:20:33 +00:00
if writeErr, ok := err.(mongo.WriteException); ok {
for _, writeError := range writeErr.WriteErrors {
if writeError.Code == 11000 {
return nil, ErrDuplicateCodeword
}
}
}
2024-01-11 16:29:53 +00:00
return nil, err
}
2024-01-11 18:20:33 +00:00
2024-01-12 11:28:22 +00:00
return req, nil
2024-01-11 16:29:53 +00:00
}
2024-01-11 19:47:54 +00:00
2024-01-12 11:28:22 +00:00
func (r *PromoCodeRepository) EditPromoCode(ctx context.Context, req *models.ReqEditPromoCode) (*models.PromoCode, error) {
promoCodeID, err := primitive.ObjectIDFromHex(req.ID)
2024-01-11 19:47:54 +00:00
if err != nil {
return nil, err
}
2024-01-12 09:42:56 +00:00
updateFields := bson.M{}
2024-01-12 11:28:22 +00:00
if req.Description != nil {
updateFields["description"] = *req.Description
2024-01-12 09:42:56 +00:00
}
2024-01-12 11:28:22 +00:00
if req.Greetings != nil {
updateFields["greetings"] = *req.Greetings
2024-01-12 09:42:56 +00:00
}
2024-01-12 11:28:22 +00:00
if req.DueTo != nil {
updateFields["dueTo"] = *req.DueTo
2024-01-12 09:42:56 +00:00
}
2024-01-12 11:28:22 +00:00
if req.ActivationCount != nil {
updateFields["activationCount"] = *req.ActivationCount
2024-01-12 09:42:56 +00:00
}
2024-01-12 11:28:22 +00:00
if req.Delete != nil {
updateFields["delete"] = *req.Delete
2024-01-12 09:42:56 +00:00
}
if len(updateFields) == 0 {
return r.GetPromoCodeByID(ctx, promoCodeID)
2024-01-11 19:47:54 +00:00
}
2024-01-12 09:42:56 +00:00
update := bson.M{"$set": updateFields}
result, err := r.mdb.UpdateOne(ctx, bson.M{"_id": promoCodeID}, update)
2024-01-11 19:47:54 +00:00
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
}
2024-01-12 11:28:22 +00:00
func (r *PromoCodeRepository) GetPromoCodesList(ctx context.Context, req *models.GetPromoCodesListReq) ([]models.PromoCode, int64, error) {
filter := bson.M{}
if req.Filter.Text != "" {
filter["$text"] = bson.M{"$search": req.Filter.Text}
}
if req.Filter.Active {
filter["delete"] = false
filter["outdated"] = false
filter["offLimit"] = false
} else {
filter["$or"] = []interface{}{
bson.M{"delete": true},
bson.M{"outdated": true},
bson.M{"offLimit": true},
}
}
opt := options.Find().SetSkip(int64(req.Page * req.Limit)).SetLimit(int64(req.Limit))
var countChan = make(chan countResult)
go func() {
defer close(countChan)
count, err := r.mdb.CountDocuments(ctx, filter)
countChan <- countResult{count, err}
}()
cursor, err := r.mdb.Find(ctx, filter, opt)
if err != nil {
return nil, 0, err
}
defer cursor.Close(ctx)
var promoCodes = make([]models.PromoCode, 0)
for cursor.Next(ctx) {
var p models.PromoCode
if err := cursor.Decode(&p); err != nil {
return nil, 0, err
}
promoCodes = append(promoCodes, p)
}
if err := cursor.Err(); err != nil {
return nil, 0, err
}
result := <-countChan
if result.err != nil {
return nil, 0, result.err
}
count := result.count
return promoCodes, count, nil
}