75 lines
2.9 KiB
Python
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)
|