package repository import ( "context" "sno/internal/models" "github.com/jackc/pgx/v5/pgxpool" ) // RewardRepository defines the interface for reward data operations. type RewardRepository interface { Create(ctx context.Context, reward *models.Reward) (*models.Reward, error) GetAllActive(ctx context.Context) ([]models.Reward, error) GetByID(ctx context.Context, id int) (*models.Reward, error) UpdateStock(ctx context.Context, id int, quantity int) error Update(ctx context.Context, id int, reward *models.Reward) (*models.Reward, error) Delete(ctx context.Context, id int) error } // postgresRewardRepository implements the RewardRepository interface. type postgresRewardRepository struct { db *pgxpool.Pool } // NewRewardRepository creates a new instance of a reward repository. func NewRewardRepository(db *pgxpool.Pool) RewardRepository { return &postgresRewardRepository{db: db} } // Create inserts a new reward into the database. func (r *postgresRewardRepository) Create(ctx context.Context, reward *models.Reward) (*models.Reward, error) { query := ` INSERT INTO rewards (title, description, image_url, price_stars, delivery_type, instructions, stock, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id, is_active, created_at ` err := r.db.QueryRow(ctx, query, reward.Title, reward.Description, reward.ImageURL, reward.PriceStars, reward.DeliveryType, reward.Instructions, reward.Stock, reward.CreatedBy, ).Scan(&reward.ID, &reward.IsActive, &reward.CreatedAt) if err != nil { return nil, err } return reward, nil } // GetAllActive retrieves all active rewards that are in stock. func (r *postgresRewardRepository) GetAllActive(ctx context.Context) ([]models.Reward, error) { query := ` SELECT id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at FROM rewards WHERE is_active = true AND (stock > 0 OR stock = -1) -- Using -1 for infinite stock ORDER BY price_stars ASC ` rows, err := r.db.Query(ctx, query) if err != nil { return nil, err } defer rows.Close() var rewards []models.Reward for rows.Next() { var p models.Reward if err := rows.Scan(&p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars, &p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt); err != nil { return nil, err } rewards = append(rewards, p) } if err := rows.Err(); err != nil { return nil, err } if rewards == nil { return []models.Reward{}, nil } return rewards, nil } // GetByID retrieves a single reward by its ID. func (r *postgresRewardRepository) GetByID(ctx context.Context, id int) (*models.Reward, error) { query := ` SELECT id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at, created_by FROM rewards WHERE id = $1 ` var p models.Reward err := r.db.QueryRow(ctx, query, id).Scan( &p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars, &p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt, &p.CreatedBy, ) if err != nil { return nil, err } return &p, nil } // UpdateStock updates the stock for a given reward. func (r *postgresRewardRepository) UpdateStock(ctx context.Context, id int, quantity int) error { query := `UPDATE rewards SET stock = stock - $1 WHERE id = $2 AND stock != -1` // -1 is infinite stock querier := getQuerier(ctx, r.db) _, err := querier.Exec(ctx, query, quantity, id) return err } // Update updates an existing reward func (r *postgresRewardRepository) Update(ctx context.Context, id int, reward *models.Reward) (*models.Reward, error) { query := ` UPDATE rewards SET title = $2, description = $3, image_url = $4, price_stars = $5, delivery_type = $6, instructions = $7, stock = $8, is_active = $9 WHERE id = $1 RETURNING id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at, created_by ` var p models.Reward err := r.db.QueryRow(ctx, query, id, reward.Title, reward.Description, reward.ImageURL, reward.PriceStars, reward.DeliveryType, reward.Instructions, reward.Stock, reward.IsActive, ).Scan( &p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars, &p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt, &p.CreatedBy, ) if err != nil { return nil, err } return &p, nil } // Delete deletes a reward func (r *postgresRewardRepository) Delete(ctx context.Context, id int) error { query := `DELETE FROM rewards WHERE id = $1` _, err := r.db.Exec(ctx, query, id) return err }