from typing import List, Optional, Dict, Any, Union, Tuple from sqlalchemy import func, desc from sqlalchemy.orm import Session from app.crud.base import CRUDBase from app.models.dex import Dex from app.models.pool import Pool from app.schemas.dex import DexCreate, DexUpdate class CRUDDex(CRUDBase[Dex, DexCreate, DexUpdate]): """CRUD operations for DEXes.""" def get_by_address(self, db: Session, *, address: str) -> Optional[Dex]: """Get a DEX by its address.""" return db.query(Dex).filter(Dex.address == address).first() def get_by_name(self, db: Session, *, name: str) -> Optional[Dex]: """Get a DEX by its name.""" return db.query(Dex).filter(Dex.name == name).first() def get_with_pool_count( self, db: Session, *, skip: int = 0, limit: int = 100 ) -> List[Tuple[Dex, int]]: """Get DEXes with count of their pools.""" return db.query( Dex, func.count(Pool.id).label('pool_count') ).outerjoin( Pool, Dex.id == Pool.dex_id ).group_by( Dex.id ).order_by( desc('pool_count') ).offset(skip).limit(limit).all() def get_with_volumes( self, db: Session, *, skip: int = 0, limit: int = 100 ) -> List[Dex]: """Get DEXes ordered by volume.""" return db.query(Dex).order_by( desc(Dex.volume_24h) ).offset(skip).limit(limit).all() def search_by_name( self, db: Session, *, query: str, skip: int = 0, limit: int = 100 ) -> List[Dex]: """Search DEXes by name.""" return db.query(Dex).filter( Dex.name.ilike(f'%{query}%') ).offset(skip).limit(limit).all() def update_volume( self, db: Session, *, dex_id: int, volume_24h: float, volume_7d: Optional[float] = None ) -> Optional[Dex]: """Update the volume statistics for a DEX.""" db_obj = db.query(Dex).filter(Dex.id == dex_id).first() if db_obj: db_obj.volume_24h = volume_24h if volume_7d is not None: db_obj.volume_7d = volume_7d db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj # Create a single instance for use in dependency injection dex = CRUDDex(Dex)