""" Archive Worker 모듈 아카이브 관련 백그라운드 작업을 처리합니다. - 소프트 삭제 (is_deleted=True 설정) """ from sqlalchemy import func, select, update from app.database.session import BackgroundSessionLocal from app.home.models import Image, Project from app.lyric.models import Lyric from app.song.models import Song, SongTimestamp from app.utils.logger import get_logger from app.video.models import Video logger = get_logger(__name__) async def soft_delete_by_task_id(task_id: str) -> dict: """ task_id에 해당하는 모든 관련 데이터를 소프트 삭제합니다. 대상 테이블 (refresh_token, social_account, user 제외): - Project - Image - Lyric - Song - SongTimestamp (suno_audio_id 기준) - Video Args: task_id: 삭제할 프로젝트의 task_id Returns: dict: 각 테이블별 업데이트된 레코드 수 """ logger.info(f"[soft_delete_by_task_id] START - task_id: {task_id}") logger.debug(f"[soft_delete_by_task_id] DEBUG - 백그라운드 태스크 시작") result = { "task_id": task_id, "project": 0, "image": 0, "lyric": 0, "song": 0, "song_timestamp": 0, "video": 0, } try: async with BackgroundSessionLocal() as session: # DEBUG: 삭제 전 각 테이블의 데이터 수 확인 video_before = await session.execute( select(func.count(Video.id)).where( Video.task_id == task_id, Video.is_deleted == False ) ) logger.debug( f"[soft_delete_by_task_id] DEBUG - 삭제 전 Video 수: {video_before.scalar() or 0}" ) song_before = await session.execute( select(func.count(Song.id)).where( Song.task_id == task_id, Song.is_deleted == False ) ) logger.debug( f"[soft_delete_by_task_id] DEBUG - 삭제 전 Song 수: {song_before.scalar() or 0}" ) lyric_before = await session.execute( select(func.count(Lyric.id)).where( Lyric.task_id == task_id, Lyric.is_deleted == False ) ) logger.debug( f"[soft_delete_by_task_id] DEBUG - 삭제 전 Lyric 수: {lyric_before.scalar() or 0}" ) image_before = await session.execute( select(func.count(Image.id)).where( Image.task_id == task_id, Image.is_deleted == False ) ) logger.debug( f"[soft_delete_by_task_id] DEBUG - 삭제 전 Image 수: {image_before.scalar() or 0}" ) project_before = await session.execute( select(func.count(Project.id)).where( Project.task_id == task_id, Project.is_deleted == False ) ) logger.debug( f"[soft_delete_by_task_id] DEBUG - 삭제 전 Project 수: {project_before.scalar() or 0}" ) # 1. Video 소프트 삭제 video_stmt = ( update(Video) .where(Video.task_id == task_id, Video.is_deleted == False) .values(is_deleted=True) ) video_result = await session.execute(video_stmt) result["video"] = video_result.rowcount logger.info(f"[soft_delete_by_task_id] Video soft deleted - count: {result['video']}") logger.debug(f"[soft_delete_by_task_id] DEBUG - Video rowcount: {video_result.rowcount}") # 2. SongTimestamp 소프트 삭제 (Song의 suno_audio_id 기준, 서브쿼리 사용) suno_subquery = ( select(Song.suno_audio_id) .where( Song.task_id == task_id, Song.suno_audio_id.isnot(None), ) .scalar_subquery() ) timestamp_stmt = ( update(SongTimestamp) .where( SongTimestamp.suno_audio_id.in_(suno_subquery), SongTimestamp.is_deleted == False, ) .values(is_deleted=True) ) timestamp_result = await session.execute(timestamp_stmt) result["song_timestamp"] = timestamp_result.rowcount logger.info( f"[soft_delete_by_task_id] SongTimestamp soft deleted - count: {result['song_timestamp']}" ) # 3. Song 소프트 삭제 song_stmt = ( update(Song) .where(Song.task_id == task_id, Song.is_deleted == False) .values(is_deleted=True) ) song_result = await session.execute(song_stmt) result["song"] = song_result.rowcount logger.info(f"[soft_delete_by_task_id] Song soft deleted - count: {result['song']}") # 4. Lyric 소프트 삭제 lyric_stmt = ( update(Lyric) .where(Lyric.task_id == task_id, Lyric.is_deleted == False) .values(is_deleted=True) ) lyric_result = await session.execute(lyric_stmt) result["lyric"] = lyric_result.rowcount logger.info(f"[soft_delete_by_task_id] Lyric soft deleted - count: {result['lyric']}") # 5. Image 소프트 삭제 image_stmt = ( update(Image) .where(Image.task_id == task_id, Image.is_deleted == False) .values(is_deleted=True) ) image_result = await session.execute(image_stmt) result["image"] = image_result.rowcount logger.info(f"[soft_delete_by_task_id] Image soft deleted - count: {result['image']}") # 6. Project 소프트 삭제 project_stmt = ( update(Project) .where(Project.task_id == task_id, Project.is_deleted == False) .values(is_deleted=True) ) project_result = await session.execute(project_stmt) result["project"] = project_result.rowcount logger.info(f"[soft_delete_by_task_id] Project soft deleted - count: {result['project']}") await session.commit() logger.info( f"[soft_delete_by_task_id] SUCCESS - task_id: {task_id}, " f"deleted: project={result['project']}, image={result['image']}, " f"lyric={result['lyric']}, song={result['song']}, " f"song_timestamp={result['song_timestamp']}, video={result['video']}" ) return result except Exception as e: logger.error(f"[soft_delete_by_task_id] EXCEPTION - task_id: {task_id}, error: {e}", exc_info=True) raise