Files
portfolio-hub/app/services/strategy_set_service.py
T

75 lines
2.9 KiB
Python

"""Strategy set service orchestration."""
from __future__ import annotations
from fastapi import Depends
from app.core.config import Settings, get_settings
from app.domain.models import StrategySet
from app.repositories.factory import get_portfolio_repository_from_settings
from app.repositories.portfolio_repository import PortfolioRepository
from app.schemas.portfolio import CreateStrategySetRequest, UpdateStrategySetRequest
def get_strategy_set_repository(settings: Settings = Depends(get_settings)) -> PortfolioRepository:
return get_portfolio_repository_from_settings(settings)
class StrategySetService:
def __init__(self, repository: PortfolioRepository) -> None:
self._repository = repository
def list(self) -> list[StrategySet]:
"""List all strategy sets."""
return self._repository.list_strategy_sets()
def get(self, strategy_set_id: str) -> StrategySet | None:
"""Get a single strategy set by ID."""
return self._repository.get_strategy_set(strategy_set_id)
def create(self, payload: CreateStrategySetRequest) -> StrategySet:
"""Create or get existing strategy set.
Uses get_or_create_strategy_set for idempotence.
"""
return self._repository.get_or_create_strategy_set(payload.name, payload.config)
def update(self, strategy_set_id: str, payload: UpdateStrategySetRequest) -> StrategySet:
"""Update a strategy set.
Since strategy sets are identified by (name, config) uniqueness,
updating requires creating a new one if name/config changes.
"""
current = self.get(strategy_set_id)
if current is None:
raise ValueError(f"Strategy set {strategy_set_id} not found")
# Use provided values or fall back to current ones
new_name = payload.name if payload.name is not None else current.name
new_config = payload.config if payload.config is not None else current.config
# If nothing changed, return current
if new_name == current.name and new_config == current.config:
return current
# Create or get the new strategy set
new_strategy_set = self._repository.get_or_create_strategy_set(new_name, new_config)
# If the new strategy set is different from current, delete the old one
# (only if it's not in use - delete_strategy_set will raise if in use)
if new_strategy_set.id != strategy_set_id:
try:
self._repository.delete_strategy_set(strategy_set_id)
except ValueError:
# If old strategy set is in use, keep it and return new one
pass
return new_strategy_set
def delete(self, strategy_set_id: str) -> None:
"""Delete a strategy set.
Raises ValueError if the strategy set is in use by any portfolio.
"""
self._repository.delete_strategy_set(strategy_set_id)