from typing import List, Optional, Dict, Any, Union, Tuple from sqlalchemy import func, desc, or_, and_ from sqlalchemy.orm import Session, joinedload from app.crud.base import CRUDBase from app.models.pool import Pool from app.models.dex import Dex from app.schemas.pool import PoolCreate, PoolUpdate class CRUDPool(CRUDBase[Pool, PoolCreate, PoolUpdate]): """CRUD operations for liquidity pools.""" def get_by_address(self, db: Session, *, address: str) -> Optional[Pool]: """Get a pool by its address.""" return db.query(Pool).filter(Pool.address == address).first() def get_by_dex( self, db: Session, *, dex_id: int, skip: int = 0, limit: int = 100 ) -> List[Pool]: """Get pools for a specific DEX.""" return db.query(Pool).filter( Pool.dex_id == dex_id ).offset(skip).limit(limit).all() def get_by_token( self, db: Session, *, token_address: str, skip: int = 0, limit: int = 100 ) -> List[Pool]: """Get pools that contain a specific token.""" return db.query(Pool).filter( or_( Pool.token_a_address == token_address, Pool.token_b_address == token_address ) ).offset(skip).limit(limit).all() def get_by_token_pair( self, db: Session, *, token_a: str, token_b: str, skip: int = 0, limit: int = 100 ) -> List[Pool]: """Get pools for a specific token pair.""" return db.query(Pool).filter( or_( and_(Pool.token_a_address == token_a, Pool.token_b_address == token_b), and_(Pool.token_a_address == token_b, Pool.token_b_address == token_a) ) ).offset(skip).limit(limit).all() def get_by_tvl_range( self, db: Session, *, min_tvl: float, max_tvl: Optional[float] = None, skip: int = 0, limit: int = 100 ) -> List[Pool]: """Get pools within a TVL range.""" query = db.query(Pool).filter(Pool.tvl >= min_tvl) if max_tvl is not None: query = query.filter(Pool.tvl <= max_tvl) return query.order_by(desc(Pool.tvl)).offset(skip).limit(limit).all() def get_pools_with_dex( self, db: Session, *, skip: int = 0, limit: int = 100 ) -> List[Tuple[Pool, Dex]]: """Get pools with their DEX information.""" return db.query( Pool, Dex ).join( Dex, Pool.dex_id == Dex.id ).order_by( desc(Pool.tvl) ).offset(skip).limit(limit).all() def update_reserves( self, db: Session, *, pool_id: int, token_a_reserve: float, token_b_reserve: float, slot: int, tvl: Optional[float] = None ) -> Optional[Pool]: """Update token reserves for a pool.""" db_obj = db.query(Pool).filter(Pool.id == pool_id).first() if db_obj and slot >= db_obj.last_updated_slot: db_obj.token_a_reserve = token_a_reserve db_obj.token_b_reserve = token_b_reserve db_obj.last_updated_slot = slot if tvl is not None: db_obj.tvl = tvl db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj def get_most_active_pools( self, db: Session, *, limit: int = 20 ) -> List[Pool]: """Get the most active pools by volume.""" return db.query(Pool).order_by( desc(Pool.volume_24h) ).limit(limit).all() # Create a single instance for use in dependency injection pool = CRUDPool(Pool)