# app/crud/user.py from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from sqlalchemy.exc import SQLAlchemyError, IntegrityError, OperationalError from typing import Optional from app.models import User as UserModel # Alias to avoid name clash from app.schemas.user import UserCreate from app.core.security import hash_password from app.core.exceptions import ( UserCreationError, EmailAlreadyRegisteredError, DatabaseConnectionError, DatabaseIntegrityError, DatabaseQueryError, DatabaseTransactionError ) async def get_user_by_email(db: AsyncSession, email: str) -> Optional[UserModel]: """Fetches a user from the database by email.""" try: async with db.begin(): result = await db.execute(select(UserModel).filter(UserModel.email == email)) return result.scalars().first() except OperationalError as e: raise DatabaseConnectionError(f"Failed to connect to database: {str(e)}") except SQLAlchemyError as e: raise DatabaseQueryError(f"Failed to query user: {str(e)}") async def create_user(db: AsyncSession, user_in: UserCreate) -> UserModel: """Creates a new user record in the database.""" try: async with db.begin(): _hashed_password = hash_password(user_in.password) db_user = UserModel( email=user_in.email, password_hash=_hashed_password, name=user_in.name ) db.add(db_user) await db.flush() # Flush to get DB-generated values await db.refresh(db_user) return db_user except IntegrityError as e: if "unique constraint" in str(e).lower(): raise EmailAlreadyRegisteredError() raise DatabaseIntegrityError(f"Failed to create user: {str(e)}") except OperationalError as e: raise DatabaseConnectionError(f"Database connection error: {str(e)}") except SQLAlchemyError as e: raise DatabaseTransactionError(f"Failed to create user: {str(e)}")