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
|
|
@ -1,36 +1,22 @@
|
|||
"""Audit routes for price history."""
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy import desc, select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from auth import require_permission
|
||||
from database import get_db
|
||||
from models import Permission, PriceHistory, User
|
||||
from price_fetcher import PAIR_BTC_EUR, SOURCE_BITFINEX, fetch_btc_eur_price
|
||||
from mappers import PriceHistoryMapper
|
||||
from models import Permission, User
|
||||
from schemas import PriceHistoryResponse
|
||||
from services.price import PriceService
|
||||
|
||||
router = APIRouter(prefix="/api/audit", tags=["audit"])
|
||||
|
||||
|
||||
def _to_price_history_response(record: PriceHistory) -> PriceHistoryResponse:
|
||||
return PriceHistoryResponse(
|
||||
id=record.id,
|
||||
source=record.source,
|
||||
pair=record.pair,
|
||||
price=record.price,
|
||||
timestamp=record.timestamp,
|
||||
created_at=record.created_at,
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Price History Endpoints
|
||||
# =============================================================================
|
||||
|
||||
PRICE_HISTORY_LIMIT = 20
|
||||
|
||||
|
||||
@router.get("/price-history", response_model=list[PriceHistoryResponse])
|
||||
async def get_price_history(
|
||||
|
|
@ -38,15 +24,10 @@ async def get_price_history(
|
|||
_current_user: User = Depends(require_permission(Permission.VIEW_AUDIT)),
|
||||
) -> list[PriceHistoryResponse]:
|
||||
"""Get the 20 most recent price history records."""
|
||||
query = (
|
||||
select(PriceHistory)
|
||||
.order_by(desc(PriceHistory.timestamp))
|
||||
.limit(PRICE_HISTORY_LIMIT)
|
||||
)
|
||||
result = await db.execute(query)
|
||||
records = result.scalars().all()
|
||||
service = PriceService(db)
|
||||
records = await service.get_recent_prices()
|
||||
|
||||
return [_to_price_history_response(record) for record in records]
|
||||
return [PriceHistoryMapper.to_response(record) for record in records]
|
||||
|
||||
|
||||
@router.post("/price-history/fetch", response_model=PriceHistoryResponse)
|
||||
|
|
@ -55,28 +36,7 @@ async def fetch_price_now(
|
|||
_current_user: User = Depends(require_permission(Permission.FETCH_PRICE)),
|
||||
) -> PriceHistoryResponse:
|
||||
"""Manually trigger a price fetch from Bitfinex."""
|
||||
price, timestamp = await fetch_btc_eur_price()
|
||||
service = PriceService(db)
|
||||
record = await service.fetch_and_store_price()
|
||||
|
||||
record = PriceHistory(
|
||||
source=SOURCE_BITFINEX,
|
||||
pair=PAIR_BTC_EUR,
|
||||
price=price,
|
||||
timestamp=timestamp,
|
||||
)
|
||||
db.add(record)
|
||||
|
||||
try:
|
||||
await db.commit()
|
||||
await db.refresh(record)
|
||||
except IntegrityError:
|
||||
# Duplicate timestamp - return the existing record
|
||||
await db.rollback()
|
||||
query = select(PriceHistory).where(
|
||||
PriceHistory.source == SOURCE_BITFINEX,
|
||||
PriceHistory.pair == PAIR_BTC_EUR,
|
||||
PriceHistory.timestamp == timestamp,
|
||||
)
|
||||
result = await db.execute(query)
|
||||
record = result.scalar_one()
|
||||
|
||||
return _to_price_history_response(record)
|
||||
return PriceHistoryMapper.to_response(record)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue