Extract price logic to PriceService
- Create PriceService with get_recent_prices() and fetch_and_store_price() - Update routes/audit.py to use PriceService instead of direct queries - Use PriceHistoryMapper consistently - Update test to patch services.price.fetch_btc_eur_price
This commit is contained in:
parent
168b67acee
commit
badb45da59
4 changed files with 324 additions and 50 deletions
70
backend/services/price.py
Normal file
70
backend/services/price.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
"""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,
|
||||
)
|
||||
self.db.add(record)
|
||||
|
||||
try:
|
||||
await self.db.commit()
|
||||
await self.db.refresh(record)
|
||||
return 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue