"""Price service for fetching and managing price history.""" from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession from exceptions import ConflictError from models import PriceHistory from price_fetcher import PAIR_BTC_EUR, SOURCE_BITFINEX, fetch_btc_eur_price from repositories.price import PriceRepository PRICE_HISTORY_LIMIT = 20 class PriceService: """Service for price-related business logic.""" def __init__(self, db: AsyncSession): self.db = db self.price_repo = PriceRepository(db) async def get_recent_prices( self, limit: int = PRICE_HISTORY_LIMIT ) -> list[PriceHistory]: """ Get recent price history records. Args: limit: Maximum number of records to return (default: 20) Returns: List of PriceHistory records, most recent first """ return await self.price_repo.get_recent(limit) async def fetch_and_store_price(self) -> PriceHistory: """ Fetch price from Bitfinex and store it in the database. Handles duplicate timestamp conflicts by returning the existing record. Returns: PriceHistory record (newly created or existing if duplicate) Raises: ConflictError: If unable to fetch or store price after retries """ price_value, timestamp = await fetch_btc_eur_price() record = PriceHistory( source=SOURCE_BITFINEX, pair=PAIR_BTC_EUR, price=price_value, timestamp=timestamp, ) try: return await self.price_repo.create(record) except IntegrityError: # Duplicate timestamp - return the existing record await self.db.rollback() existing_record = await self.price_repo.get_by_timestamp( timestamp, SOURCE_BITFINEX, PAIR_BTC_EUR ) if existing_record: return existing_record # This should not happen, but handle gracefully raise ConflictError("Failed to fetch or store price") from None