import uuid from datetime import datetime, timezone from sqlalchemy import DateTime, JSON, func from sqlalchemy.ext.asyncio import AsyncSession from sqlmodel import Field, SQLModel, select def _now() -> datetime: return datetime.now(timezone.utc) class Assessments(SQLModel, table=True): __tablename__ = "assessments" id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) inbox_id: int | None = Field(default=None, index=True, foreign_key="inbox.id") manual_upload_candidate_id: uuid.UUID | None = Field( default=None, index=True, foreign_key="manual_upload_candidate.id" ) job_post_id: uuid.UUID | None = Field(default=None, foreign_key="job_posts.id") assessment_type: str assessment_status: str = Field(default="pending") score: int | None = Field(default=None) section_scores: list | None = Field(default=None, sa_type=JSON) duration_minutes: int | None = Field(default=None) assigned_at: datetime | None = Field(default=None, sa_type=DateTime(timezone=True)) due_at: datetime | None = Field(default=None, sa_type=DateTime(timezone=True)) completed_at: datetime | None = Field(default=None, sa_type=DateTime(timezone=True)) reminded_at: datetime | None = Field(default=None, sa_type=DateTime(timezone=True)) created_by: uuid.UUID = Field(foreign_key="users.id") created_at: datetime = Field(default_factory=_now, sa_type=DateTime(timezone=True)) updated_at: datetime = Field(default_factory=_now, sa_type=DateTime(timezone=True)) is_deleted: bool = Field(default=False) @staticmethod def _as_uuid(record_id) -> uuid.UUID | None: if record_id in (None, ""): return None try: return uuid.UUID(str(record_id)) except ValueError: return None @classmethod async def get_assessment_by_id(cls, session: AsyncSession, record_id): uid = cls._as_uuid(record_id) if uid is None: return None result = await session.execute( select(cls).where(cls.id == uid, cls.is_deleted == False) # noqa: E712 ) return result.scalars().first() @classmethod async def fetch_assessments( cls, session: AsyncSession, *, assessment_id=None, inbox_id=None, manual_upload_candidate_id=None, job_post_id=None, assessment_status=None, top: int | None = None, skip: int = 0, ): if assessment_id: row = await cls.get_assessment_by_id(session, assessment_id) if row is None: return [], 0 return [row], 1 statement = select(cls).where(cls.is_deleted == False) # noqa: E712 if inbox_id is not None: statement = statement.where(cls.inbox_id == int(inbox_id)) if manual_upload_candidate_id is not None: uid = cls._as_uuid(manual_upload_candidate_id) if uid is None: return [], 0 statement = statement.where(cls.manual_upload_candidate_id == uid) if job_post_id is not None: uid = cls._as_uuid(job_post_id) if uid is None: return [], 0 statement = statement.where(cls.job_post_id == uid) if assessment_status: statement = statement.where(cls.assessment_status == assessment_status) count_statement = select(func.count()).select_from(statement.subquery()) total = (await session.execute(count_statement)).scalar_one() statement = statement.order_by(cls.created_at.desc()) if skip: statement = statement.offset(skip) if top is not None: statement = statement.limit(top) result = await session.execute(statement) return list(result.scalars().all()), total @classmethod async def count_by_status(cls, session: AsyncSession): statement = ( select(cls.assessment_status, func.count()) .where(cls.is_deleted == False) # noqa: E712 .group_by(cls.assessment_status) ) result = await session.execute(statement) counts = {} for status, n in result.all(): counts[status] = int(n or 0) return counts @classmethod async def insert_assessment(cls, session: AsyncSession, fields: dict): row = cls(**fields) session.add(row) await session.commit() return await cls.get_assessment_by_id(session, row.id) @classmethod async def update_assessment(cls, session: AsyncSession, record_id, fields: dict): row = await cls.get_assessment_by_id(session, record_id) if not row: return None for key, value in fields.items(): setattr(row, key, value) row.updated_at = _now() session.add(row) await session.commit() await session.refresh(row) return row @classmethod async def soft_delete_assessment(cls, session: AsyncSession, record_id): row = await cls.get_assessment_by_id(session, record_id) if not row: return None row.is_deleted = True row.updated_at = _now() session.add(row) await session.commit() return row import users.models as _users_models # noqa: E402, F401