Files
steam_analyzer/internal/service/item.go
2026-01-17 22:45:02 +03:00

130 lines
3.4 KiB
Go

// Package service for service's
package service
import (
"context"
"database/sql"
"errors"
"log/slog"
"math"
"steam_analyzer/internal/domain"
"steam_analyzer/internal/repository"
"steam_analyzer/internal/utils"
"steam_analyzer/internal/utils/slogutils"
"steam_analyzer/pkg/postgresql"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgconn"
)
type ItemRepository interface {
AddItem(ctx context.Context, item domain.DBItem) error
AddItemHistory(ctx context.Context, dbItemHistory domain.DBItemHistory) error
GetItemByClassID(ctx context.Context, classID string) (*domain.SteamItem, error)
GetItemPriceHistoryByID(ctx context.Context, itemID uuid.UUID, limit int, offset int) ([]domain.ItemPriceHistory, error)
GetItemsWithLastPriceByName(ctx context.Context, name string) ([]repository.ItemWithLastPrice, error)
}
type ItemService struct {
logger *slog.Logger
itemRepo ItemRepository
}
func NewItemService(logger *slog.Logger, itemRepo ItemRepository) *ItemService {
return &ItemService{
logger: logger,
itemRepo: itemRepo,
}
}
func (s ItemService) AddItemWithHistory(ctx context.Context, item domain.SteamItem) error {
searchedItem, err := s.itemRepo.GetItemByClassID(ctx, item.ClassID)
if err != nil {
switch {
case errors.Is(err, sql.ErrNoRows):
s.logger.Info("Item is new, creating it")
default:
return err
}
}
if searchedItem != nil {
item.ID = searchedItem.ID
} else {
item.ID = uuid.New()
err = s.itemRepo.AddItem(ctx, item.ToDB())
if err != nil {
if pgErr, ok := err.(*pgconn.PgError); ok && pgErr.Code == postgresql.ErrConstraintUnique {
s.logger.Error("Error while adding item", slog.String("error", "Item already exists"))
} else {
s.logger.Error("Error while adding item", slogutils.Error(err))
return err
}
}
}
err = s.itemRepo.AddItemHistory(ctx, item.ToDBHistory())
if err != nil {
s.logger.Error("Error while adding item history", slogutils.Error(sql.ErrNoRows))
return err
}
return nil
}
func (s ItemService) GetItemWithPriceHistoryByClassID(ctx context.Context, classID string, limit int, offset int) (*domain.SteamItem, error) {
steamItem, err := s.itemRepo.GetItemByClassID(ctx, classID)
if err != nil {
s.logger.Error("Error while getting item by class id", slogutils.Error(err))
return nil, err
}
itemPriceHistory, err := s.itemRepo.GetItemPriceHistoryByID(ctx, steamItem.ID, limit, offset)
if err != nil {
s.logger.Error("Error while getting item price history by id", slogutils.Error(err))
return nil, err
}
steamItem.History = itemPriceHistory
return steamItem, nil
}
func (s ItemService) GetAllItemsWithLastPrice(ctx context.Context, itemName string) ([]repository.ItemWithLastPrice, error) {
s.logger.Info("ItemService.GetAllItemsWithLastPrice", slog.String("item name is", itemName))
items, err := s.itemRepo.GetItemsWithLastPriceByName(ctx, itemName)
if err != nil {
s.logger.Error("Error while getting item with last price", slogutils.Error(err))
return nil, err
}
for i, item := range items {
items[i].Price = formatPrice(item.Price)
items[i].Date = formatDate(item.Date)
}
return items, nil
}
func formatPrice(price float64) float64 {
formattedPrice := price / 100 * utils.CURRENCY_RUB
formattedPrice = math.Round(formattedPrice*100) / 100
return formattedPrice
}
func formatDate(date time.Time) time.Time {
location, _ := time.LoadLocation("Europe/Moscow")
foramettedDate := date.In(location)
return foramettedDate
}