""" Avatar CRUD 操作 ================ 形象克隆记录的数据访问层。 """ from datetime import UTC, datetime, timedelta from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.crud.base import CRUDBase from app.models.avatar import Avatar from app.schemas.avatar import AvatarCreate, AvatarUpdate class CRUDAvatar(CRUDBase[Avatar, AvatarCreate, AvatarUpdate]): """Avatar 数据访问对象""" def __init__(self) -> None: super().__init__(Avatar) async def get_multi_by_user( self, db: AsyncSession, *, user_id: str, skip: int = 0, limit: int = 100 ) -> list[Avatar]: """获取用户的形象列表(排除已软删除)""" result = await db.execute( select(Avatar) .where(Avatar.user_id == user_id) .where(Avatar.deleted_at.is_(None)) .offset(skip) .limit(limit) .order_by(Avatar.created_at.desc()) ) return list(result.scalars().all()) async def soft_delete(self, db: AsyncSession, *, id: str, commit: bool = True) -> Avatar | None: """软删除形象记录""" obj = await self.get(db, id) if obj: obj.deleted_at = datetime.now(UTC) if commit: await db.commit() await db.refresh(obj) else: await db.flush() return obj async def get_stuck_tasks( self, db: AsyncSession, processing_statuses: list[str], timeout_minutes: int = 30, limit: int = 100, ) -> list[Avatar]: """获取卡住的任务(超过指定时间未更新的处理中任务) Args: db: 数据库会话 processing_statuses: 需要检查的处理中状态列表 timeout_minutes: 超时时间(分钟) limit: 最大返回数量 """ timeout_threshold = datetime.now(UTC) - timedelta(minutes=timeout_minutes) result = await db.execute( select(Avatar) .where(Avatar.status.in_(processing_statuses)) .where(Avatar.deleted_at.is_(None)) .where(Avatar.updated_at < timeout_threshold) .limit(limit) .order_by(Avatar.updated_at.asc()) ) return list(result.scalars().all()) async def get_by_status_in( self, db: AsyncSession, statuses: list[str], updated_before: datetime | None = None, limit: int = 100, ) -> list[Avatar]: """根据状态列表查询任务 Args: db: 数据库会话 statuses: 状态列表 updated_before: 更新时间早于该时间的记录 limit: 最大返回数量 """ query = select(Avatar).where(Avatar.status.in_(statuses)).where(Avatar.deleted_at.is_(None)) if updated_before: query = query.where(Avatar.updated_at < updated_before) query = query.limit(limit).order_by(Avatar.updated_at.asc()) result = await db.execute(query) return list(result.scalars().all()) # 全局单例 avatar = CRUDAvatar()