implemented service layer

This commit is contained in:
mzfarshad 2026-04-10 18:52:30 +03:30
parent 73411137c8
commit 3d5e4e473b
4 changed files with 235 additions and 0 deletions

View File

@ -1 +1,21 @@
package service
import (
"git.gocasts.ir/ebhomengo/niki/types"
)
type CartItem struct {
ProductID types.ID
Quantity int
Price types.Price
Name string
AddedAt int64
}
type Cart struct {
UserID types.ID
Items []CartItem
TotalPrice types.Price
ExpireAt int64
CreatedAt int64
}

View File

@ -1 +1,30 @@
package service
import "git.gocasts.ir/ebhomengo/niki/types"
type AddToCartRequest struct {
UserID types.ID `json:"user_id"`
ProductID types.ID `json:"product_id"`
Quantity int `json:"quantity"`
Price types.Price `json:"price"`
Name string `json:"name"`
}
type GetCartResponse struct {
UserID types.ID `json:"user_id"`
Items []CartItem `json:"items"`
TotalPrice types.Price `json:"total_price"`
CreatedAt int64 `json:"created_at"`
ExpireAt int64 `json:"expire_at"`
}
type RemoveFromCartRequest struct {
UserID types.ID `json:"user_id"`
ProductID types.ID `json:"product_id"`
}
type UpdateQuantityRequest struct {
UserID types.ID `json:"user_id"`
ProductID types.ID `json:"product_id"`
Quantity int `json:"quantity"`
}

View File

@ -1 +1,96 @@
package service
import (
"context"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"git.gocasts.ir/ebhomengo/niki/types"
"time"
)
type Repository interface {
AddItem(ctx context.Context, userID types.ID, cart CartItem) error
GetCart(ctx context.Context, userID types.ID) (Cart, error)
DeleteItem(ctx context.Context, userID, productID types.ID) error
UpdateQuantity(ctx context.Context, userID, productID types.ID, quantity int) error
DeleteCart(ctx context.Context, userID types.ID) error
}
type Service struct {
validate Validate
repo Repository
}
func New(val Validate, repo Repository) Service {
return Service{validate: val, repo: repo}
}
func (s Service) AddToBasket(ctx context.Context, req AddToCartRequest) error {
const op = "shoppingbasketapp.service.AddToBasket"
if err := s.validate.ValidateAddToCart(req); err != nil {
return err
}
return s.repo.AddItem(ctx, req.UserID, CartItem{
ProductID: req.ProductID,
Quantity: req.Quantity,
Price: req.Price,
Name: req.Name,
AddedAt: time.Now().UnixNano(),
})
}
func (s Service) GetCart(ctx context.Context, userID types.ID) (GetCartResponse, error) {
const op = "shoppingbasketapp.service.GetCart"
if userID < 1 {
return GetCartResponse{}, richerror.New(op).WithKind(richerror.KindInvalid).WithMessage("invalid user id")
}
res, err := s.repo.GetCart(ctx, userID)
if err != nil {
return GetCartResponse{}, richerror.New(op).WithErr(err)
}
return GetCartResponse{
UserID: res.UserID,
Items: res.Items,
TotalPrice: res.TotalPrice,
CreatedAt: res.CreatedAt,
ExpireAt: res.ExpireAt,
}, nil
}
func (s Service) RemoveFromCart(ctx context.Context, req RemoveFromCartRequest) error {
const op = "shoppingbaskerapp.service.RemoveFromCart"
if err := s.validate.ValidateRemoveFromCart(req); err != nil {
return err
}
return s.repo.DeleteItem(ctx, req.UserID, req.ProductID)
}
func (s Service) UpdateQuantity(ctx context.Context, req UpdateQuantityRequest) error {
const op = "shoppingbaskerapp.service.UpdateQuantity"
if err := s.validate.ValidateUpdateQuantity(req); err != nil {
return err
}
if req.Quantity == 0 {
return s.repo.DeleteItem(ctx, req.UserID, req.ProductID)
}
return s.repo.UpdateQuantity(ctx, req.UserID, req.ProductID, req.Quantity)
}
func (s Service) ClearCart(ctx context.Context, userID types.ID) error {
const op = "shoppingbaskerapp.service.ClearCart"
if userID < 1 {
return richerror.New(op).WithKind(richerror.KindInvalid).
WithMessage("invalid user id")
}
return s.repo.DeleteCart(ctx, userID)
}

View File

@ -0,0 +1,91 @@
package service
import (
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
validation "github.com/go-ozzo/ozzo-validation/v4"
)
const (
ErrValidationPositive = "must be positive"
ErrValidationInvalidInput = "invalid input"
)
type Validate struct{}
func NewValidate() Validate {
return Validate{}
}
func (v Validate) ValidateAddToCart(req AddToCartRequest) error {
const op = "shoppingbasketapp.service.AddToCart"
if err := validation.ValidateStruct(&req,
validation.Field(&req.UserID, validation.Required),
validation.Field(&req.ProductID, validation.Required),
validation.Field(&req.Price, validation.Required, validation.Min(int64(1)).Error(ErrValidationPositive)),
validation.Field(&req.Quantity, validation.Min(int(1)).Error(ErrValidationPositive)),
validation.Field(&req.Name, validation.Required)); err != nil {
fieldErr := make(map[string]interface{})
vErr, ok := err.(validation.Errors)
if ok {
for key, value := range vErr {
if value != nil {
fieldErr[key] = value.Error()
}
}
}
return richerror.New(op).WithMessage(ErrValidationInvalidInput).
WithMeta(fieldErr).WithErr(err).WithKind(richerror.KindInvalid)
}
return nil
}
func (v Validate) ValidateRemoveFromCart(req RemoveFromCartRequest) error {
const op = "shoppingbasketapp.service.ValidateRemoveFromCart"
if err := validation.ValidateStruct(&req,
validation.Field(&req.UserID, validation.Required),
validation.Field(&req.ProductID, validation.Required)); err != nil {
fieldErrs := make(map[string]interface{})
vErr, ok := err.(validation.Errors)
if ok {
for key, value := range vErr {
if value != nil {
fieldErrs[key] = value.Error()
}
}
}
return richerror.New(op).WithMessage(ErrValidationInvalidInput).
WithKind(richerror.KindInvalid).WithMeta(fieldErrs).WithErr(err)
}
return nil
}
func (v Validate) ValidateUpdateQuantity(req UpdateQuantityRequest) error {
const op = "shoppingbasketapp.service.ValidateUpdateQuantity"
if err := validation.ValidateStruct(&req,
validation.Field(&req.UserID, validation.Required),
validation.Field(&req.ProductID, validation.Required),
validation.Field(&req.Quantity, validation.Required, validation.Min(int(1)))); err != nil {
fieldErrs := make(map[string]interface{})
vErr, ok := err.(validation.Errors)
if ok {
for key, value := range vErr {
if value != nil {
fieldErrs[key] = value.Error()
}
}
}
return richerror.New(op).WithMessage(ErrValidationInvalidInput).
WithKind(richerror.KindInvalid).WithMeta(fieldErrs).WithErr(err)
}
return nil
}