from __future__ import annotations from typing import Optional from sqlalchemy import select, func, update from sqlalchemy.ext.asyncio import AsyncSession from models.ghost_content import Post, PostLike async def toggle_post_like( session: AsyncSession, user_id: int, post_id: int, ) -> tuple[bool, Optional[str]]: """ Toggle a post like for a given user using soft deletes. Returns (liked_state, error_message). - If error_message is not None, an error occurred. - liked_state indicates whether post is now liked (True) or unliked (False). """ # Verify post exists post_exists = await session.scalar( select(Post.id).where(Post.id == post_id, Post.deleted_at.is_(None)) ) if not post_exists: return False, "Post not found" # Check if like exists (not deleted) existing = await session.scalar( select(PostLike).where( PostLike.user_id == user_id, PostLike.post_id == post_id, PostLike.deleted_at.is_(None), ) ) if existing: # Unlike: soft delete the like await session.execute( update(PostLike) .where( PostLike.user_id == user_id, PostLike.post_id == post_id, PostLike.deleted_at.is_(None), ) .values(deleted_at=func.now()) ) return False, None else: # Like: add a new like new_like = PostLike( user_id=user_id, post_id=post_id, ) session.add(new_like) return True, None