package pricing import ( "context" "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgconn" "gorm.io/gorm" ) var ( ErrNotFound = errors.New("price tier not found") ErrInvalidReference = errors.New("product or unit does not exist") ) type Repository interface { Create(ctx context.Context, t *PriceTier) error FindByID(ctx context.Context, id uuid.UUID) (*PriceTier, error) ListByProduct(ctx context.Context, productID uuid.UUID) ([]*PriceTier, error) Update(ctx context.Context, t *PriceTier) error Delete(ctx context.Context, id uuid.UUID) error } type gormRepository struct { db *gorm.DB } func NewRepository(db *gorm.DB) Repository { return &gormRepository{db: db} } func (r *gormRepository) Create(ctx context.Context, t *PriceTier) error { if err := r.db.WithContext(ctx).Create(t).Error; err != nil { if isForeignKeyViolation(err) { return ErrInvalidReference } return err } return nil } func (r *gormRepository) FindByID(ctx context.Context, id uuid.UUID) (*PriceTier, error) { var t PriceTier err := r.db.WithContext(ctx).Where("id = ?", id).First(&t).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrNotFound } if err != nil { return nil, err } return &t, nil } func (r *gormRepository) ListByProduct(ctx context.Context, productID uuid.UUID) ([]*PriceTier, error) { var list []*PriceTier err := r.db.WithContext(ctx).Where("product_id = ?", productID).Order("position asc, quantity asc").Find(&list).Error if err != nil { return nil, err } return list, nil } func (r *gormRepository) Update(ctx context.Context, t *PriceTier) error { err := r.db.WithContext(ctx).Save(t).Error if isForeignKeyViolation(err) { return ErrInvalidReference } return err } func (r *gormRepository) Delete(ctx context.Context, id uuid.UUID) error { res := r.db.WithContext(ctx).Delete(&PriceTier{}, "id = ?", id) if res.Error != nil { return res.Error } if res.RowsAffected == 0 { return ErrNotFound } return nil } func isForeignKeyViolation(err error) bool { var pgErr *pgconn.PgError return errors.As(err, &pgErr) && pgErr.Code == "23503" }