vibeStonk/server/services/stockService.go
2025-06-12 16:57:42 -04:00

116 lines
2.6 KiB
Go

package services
import (
"database/sql"
"errors"
"fmt"
"hash/fnv"
"sync"
models "vibeStonk/server/models/v1"
"vibeStonk/server/repository"
)
var (
ErrExistingStock = errors.New("stock with symbol exists")
)
func NewStockService(config *repository.Config) (StockService, error) {
db, err := repository.GetStockConnector(config)
if err != nil {
return nil, fmt.Errorf("failed to initialize stock service: %w", err)
}
stockRepo, err := repository.NewStockRepo(config, db)
if err != nil {
return nil, fmt.Errorf("failed to initialize stockRepo: %w", err)
}
return &stockService{db: db, lock: &sync.Mutex{}, stockRepo: stockRepo}, nil
}
type StockService interface {
NewStock(symbol, name string) (*models.Stock, error)
// Update(*models.Stock)(*models.Stock, error)
Get(id int) (*models.Stock, error)
GetBySymbol(symbol string) (*models.Stock, error)
GetAll() ([]*models.Stock, error)
GetByIDs(ids []int) ([]*models.Stock, error)
Close() error
}
type stockService struct {
db *sql.DB
lock *sync.Mutex
stockRepo repository.StockRepo
}
func (s *stockService) Get(id int) (*models.Stock, error) {
return s.stockRepo.Get(int64(id))
}
func (s *stockService) GetBySymbol(symbol string) (*models.Stock, error) {
return s.stockRepo.GetBySymbol(symbol)
}
func (s *stockService) NewStock(symbol, name string) (*models.Stock, error) {
s.lock.Lock()
defer s.lock.Unlock()
stock := &models.Stock{
Id: -1,
Symbol: symbol,
Name: name,
Color: createColor(symbol, name),
}
stonk, err := s.stockRepo.GetBySymbol(stock.Symbol)
if err == nil || stonk != nil {
return nil, ErrExistingStock
}
stock, err = s.stockRepo.Create(stock)
if err != nil {
return nil, fmt.Errorf("failed to create new stock: %w", err)
}
return stock, nil
}
func (s *stockService) GetAll() ([]*models.Stock, error) {
stocks, err := s.stockRepo.List()
if err != nil {
return nil, fmt.Errorf("failed to get all stocks: %w", err)
}
return stocks, nil
}
func (s *stockService) GetByIDs(ids []int) ([]*models.Stock, error) {
stocks, err := s.stockRepo.GetByIDs(ids)
if err != nil {
return nil, fmt.Errorf("failed to filter stocks by IDs: %w", err)
}
return stocks, nil
}
func (s *stockService) Close() error {
return s.db.Close()
}
// helpers
func createColor(symbol, name string) string {
// Generate a deterministic color based on symbol+name formatted as #RRGGBB hex
h := fnv.New32a()
h.Write([]byte(symbol + name))
hash := h.Sum32()
// Use the hash to generate RGB values
r := (hash & 0xFF0000) >> 16
g := (hash & 0x00FF00) >> 8
b := hash & 0x0000FF
// Format as #RRGGBB hex
return fmt.Sprintf("#%02X%02X%02X", r, g, b)
}