basket-service/src/internal/app/service/basket.go
Piotr Biernat 751e1c70e6
Some checks failed
continuous-integration/drone/push Build is failing
Refactoring - added Functional Option pattern
2023-04-04 00:57:11 +02:00

140 lines
4.1 KiB
Go

package service
import (
"context"
"git.pbiernat.dev/egommerce/api-entities/model"
"git.pbiernat.dev/egommerce/basket-service/internal/app/event"
"git.pbiernat.dev/egommerce/go-api-pkg/api"
"git.pbiernat.dev/egommerce/go-api-pkg/fluentd"
"git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq"
"github.com/georgysavva/scany/v2/pgxscan"
"github.com/go-redis/redis/v8"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/streadway/amqp"
)
const (
ServiceUserAgent = "basket-httpclient"
)
type BasketService struct {
dbConn *pgxpool.Pool
redis *redis.Client
ebCh *amqp.Channel
log *fluentd.Logger
}
func NewBasketService(dbConn *pgxpool.Pool, redis *redis.Client, chn *amqp.Channel, log *fluentd.Logger) *BasketService {
return &BasketService{dbConn, redis, chn, log}
}
func (s *BasketService) Log(format string, val ...any) {
s.log.Log(format, val...)
}
func (s *BasketService) CreateBasket(ctx context.Context, basketID string) (*model.BasketModel, error) {
sql := `INSERT INTO basket.basket(id) VALUES($1)`
if _, err := s.dbConn.Exec(ctx, sql, basketID); err != nil {
return nil, err
}
return &model.BasketModel{ID: basketID}, nil // FIXME
}
func (s *BasketService) FetchFromDB(ctx context.Context, basketID string) (*model.BasketModel, error) {
basket := new(model.BasketModel)
err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id,state,created_at,updated_at FROM basket.basket WHERE id=$1 LIMIT 1`, basketID)
if err != nil {
return nil, err
}
return basket, nil
}
func (s *BasketService) FetchItems(ctx context.Context, basketID string) ([]*model.BasketItemModel, error) {
items := []*model.BasketItemModel{}
sql := `SELECT id,basket_id,product_id,quantity,price,created_at FROM basket.basket_item WHERE basket_id=$1`
rows, err := s.dbConn.Query(ctx, sql, basketID)
if err != nil {
// s.Log("Fetch basket items error: %v", err)
return nil, err
}
if err := pgxscan.ScanAll(&items, rows); err != nil {
// s.Log("Fetch basket items error: %v", err)
return nil, err
}
return items, nil
}
func (s *BasketService) FetchItem(ctx context.Context, basketID string, productID int) (*model.BasketItemModel, error) {
item := new(model.BasketItemModel)
sql := `SELECT id,basket_id,product_id,quantity,price,created_at FROM basket.basket_item WHERE basket_id=$1 AND product_id=$2 LIMIT 1`
err := pgxscan.Get(ctx, s.dbConn, item, sql, basketID, productID)
if err != nil {
return nil, err
}
return item, nil
}
func (s *BasketService) AddItem(ctx context.Context, itemID int, basketID string, qty int) error {
var price float64 = 0
pricingAPI := api.NewPricingAPI(ServiceUserAgent, s.redis)
productPrice, err := pricingAPI.GetProductPrice(itemID)
if err == nil {
price = productPrice.Price
}
sql := `INSERT INTO basket.basket_item(basket_id,product_id,price,quantity) VALUES($1,$2,$3,$4)`
if _, err := s.dbConn.Exec(ctx, sql, basketID, itemID, price, qty); err != nil {
return err
}
// update basket updated_at field...
return nil
}
func (s *BasketService) RemoveItem(ctx context.Context, itemID int, basketID string) error {
sql := `DELETE FROM basket.basket_item WHERE basket_id=$1 AND product_id=$2`
if _, err := s.dbConn.Exec(ctx, sql, basketID, itemID); err != nil {
return err
}
// update basket updated_at field...
return nil
}
func (s *BasketService) UpdateItem(ctx context.Context, item *model.BasketItemModel, qty int) error {
var price float64 = 0
pricingAPI := api.NewPricingAPI(ServiceUserAgent, s.redis)
productPrice, err := pricingAPI.GetProductPrice(item.ProductID)
if err == nil {
price = productPrice.Price
}
sql := `UPDATE basket.basket_item SET quantity=$1, price=$2 WHERE basket_id=$3 AND product_id=$4`
if _, err := s.dbConn.Exec(ctx, sql, qty, price, item.BasketID, item.ProductID); err != nil {
return err
}
// update basket updated_at field...
return nil
}
func (s *BasketService) Checkout(reqID, basketID string) (string, error) {
s.log.Log("Creating initial order from basket#:%s", basketID)
msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} // FIXME: send more info...
rabbitmq.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg)
return basketID, nil
}