package repository import ( "context" "fmt" "apskel-pos-be/internal/entities" "gorm.io/gorm" ) type CampaignRepository interface { Create(ctx context.Context, campaign *entities.Campaign) error GetByID(ctx context.Context, id string) (*entities.Campaign, error) List(ctx context.Context, req *entities.ListCampaignsRequest) ([]entities.Campaign, int64, error) Update(ctx context.Context, campaign *entities.Campaign) error Delete(ctx context.Context, id string) error GetActiveCampaigns(ctx context.Context) ([]entities.Campaign, error) GetCampaignsForApp(ctx context.Context) ([]entities.Campaign, error) } type campaignRepository struct { db *gorm.DB } func NewCampaignRepository(db *gorm.DB) CampaignRepository { return &campaignRepository{ db: db, } } func (r *campaignRepository) Create(ctx context.Context, campaign *entities.Campaign) error { return r.db.WithContext(ctx).Create(campaign).Error } func (r *campaignRepository) GetByID(ctx context.Context, id string) (*entities.Campaign, error) { var campaign entities.Campaign if err := r.db.WithContext(ctx).Preload("Rules").Where("id = ?", id).First(&campaign).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, fmt.Errorf("campaign not found") } return nil, fmt.Errorf("failed to get campaign: %w", err) } return &campaign, nil } func (r *campaignRepository) List(ctx context.Context, req *entities.ListCampaignsRequest) ([]entities.Campaign, int64, error) { var campaigns []entities.Campaign var total int64 query := r.db.WithContext(ctx).Model(&entities.Campaign{}) // Apply filters if req.Search != "" { query = query.Where("name ILIKE ? OR description ILIKE ?", "%"+req.Search+"%", "%"+req.Search+"%") } if req.Type != "" { query = query.Where("type = ?", req.Type) } if req.IsActive != nil { query = query.Where("is_active = ?", *req.IsActive) } if req.ShowOnApp != nil { query = query.Where("show_on_app = ?", *req.ShowOnApp) } if req.StartDate != nil { query = query.Where("start_date >= ?", *req.StartDate) } if req.EndDate != nil { query = query.Where("end_date <= ?", *req.EndDate) } // Count total records if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count campaigns: %w", err) } // Apply pagination if req.Page > 0 && req.Limit > 0 { offset := (req.Page - 1) * req.Limit query = query.Offset(offset).Limit(req.Limit) } // Apply sorting query = query.Order("position ASC, created_at DESC") if err := query.Preload("Rules").Find(&campaigns).Error; err != nil { return nil, 0, fmt.Errorf("failed to list campaigns: %w", err) } return campaigns, total, nil } func (r *campaignRepository) Update(ctx context.Context, campaign *entities.Campaign) error { return r.db.WithContext(ctx).Save(campaign).Error } func (r *campaignRepository) Delete(ctx context.Context, id string) error { return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { // Delete campaign (rules will be deleted by CASCADE) if err := tx.Where("id = ?", id).Delete(&entities.Campaign{}).Error; err != nil { return fmt.Errorf("failed to delete campaign: %w", err) } return nil }) } func (r *campaignRepository) GetActiveCampaigns(ctx context.Context) ([]entities.Campaign, error) { var campaigns []entities.Campaign now := "now()" if err := r.db.WithContext(ctx).Where("is_active = ? AND start_date <= ? AND end_date >= ?", true, now, now).Preload("Rules").Find(&campaigns).Error; err != nil { return nil, fmt.Errorf("failed to get active campaigns: %w", err) } return campaigns, nil } func (r *campaignRepository) GetCampaignsForApp(ctx context.Context) ([]entities.Campaign, error) { var campaigns []entities.Campaign now := "now()" if err := r.db.WithContext(ctx).Where("is_active = ? AND show_on_app = ? AND start_date <= ? AND end_date >= ?", true, true, now, now).Preload("Rules").Order("position ASC").Find(&campaigns).Error; err != nil { return nil, fmt.Errorf("failed to get campaigns for app: %w", err) } return campaigns, nil } // Campaign Rule Repository type CampaignRuleRepository interface { Create(ctx context.Context, rule *entities.CampaignRule) error GetByID(ctx context.Context, id string) (*entities.CampaignRule, error) List(ctx context.Context, req *entities.ListCampaignRulesRequest) ([]entities.CampaignRule, int64, error) Update(ctx context.Context, rule *entities.CampaignRule) error Delete(ctx context.Context, id string) error GetByCampaignID(ctx context.Context, campaignID string) ([]entities.CampaignRule, error) } type campaignRuleRepository struct { db *gorm.DB } func NewCampaignRuleRepository(db *gorm.DB) CampaignRuleRepository { return &campaignRuleRepository{ db: db, } } func (r *campaignRuleRepository) Create(ctx context.Context, rule *entities.CampaignRule) error { if err := r.db.WithContext(ctx).Create(rule).Error; err != nil { return fmt.Errorf("failed to create campaign rule: %w", err) } return nil } func (r *campaignRuleRepository) GetByID(ctx context.Context, id string) (*entities.CampaignRule, error) { var rule entities.CampaignRule if err := r.db.WithContext(ctx).Where("id = ?", id).First(&rule).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, fmt.Errorf("campaign rule not found") } return nil, fmt.Errorf("failed to get campaign rule: %w", err) } return &rule, nil } func (r *campaignRuleRepository) List(ctx context.Context, req *entities.ListCampaignRulesRequest) ([]entities.CampaignRule, int64, error) { var rules []entities.CampaignRule var total int64 query := r.db.WithContext(ctx).Model(&entities.CampaignRule{}) // Apply filters if req.CampaignID != "" { query = query.Where("campaign_id = ?", req.CampaignID) } if req.RuleType != "" { query = query.Where("rule_type = ?", req.RuleType) } if req.RewardType != "" { query = query.Where("reward_type = ?", req.RewardType) } // Count total records if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count campaign rules: %w", err) } // Apply pagination if req.Page > 0 && req.Limit > 0 { offset := (req.Page - 1) * req.Limit query = query.Offset(offset).Limit(req.Limit) } // Apply sorting query = query.Order("created_at DESC") if err := query.Find(&rules).Error; err != nil { return nil, 0, fmt.Errorf("failed to list campaign rules: %w", err) } return rules, total, nil } func (r *campaignRuleRepository) Update(ctx context.Context, rule *entities.CampaignRule) error { if err := r.db.WithContext(ctx).Save(rule).Error; err != nil { return fmt.Errorf("failed to update campaign rule: %w", err) } return nil } func (r *campaignRuleRepository) Delete(ctx context.Context, id string) error { if err := r.db.WithContext(ctx).Where("id = ?", id).Delete(&entities.CampaignRule{}).Error; err != nil { return fmt.Errorf("failed to delete campaign rule: %w", err) } return nil } func (r *campaignRuleRepository) GetByCampaignID(ctx context.Context, campaignID string) ([]entities.CampaignRule, error) { var rules []entities.CampaignRule if err := r.db.WithContext(ctx).Where("campaign_id = ?", campaignID).Find(&rules).Error; err != nil { return nil, fmt.Errorf("failed to get campaign rules by campaign ID: %w", err) } return rules, nil }