"""Dispatch repositories — Phase 10.5.""" from __future__ import annotations from typing import Sequence from uuid import UUID from sqlalchemy import func, select from app.models.dispatch import DispatchJob, JobAssignment from app.repositories.base import TenantBaseRepository from app.specifications.dispatch import DispatchJobListSpec, JobAssignmentListSpec class DispatchJobRepository(TenantBaseRepository[DispatchJob]): model = DispatchJob async def get_by_code(self, tenant_id: UUID, code: str) -> DispatchJob | None: stmt = select(self.model).where( self.model.tenant_id == tenant_id, self.model.code == code, self.model.is_deleted.is_(False), ) result = await self.session.execute(stmt) return result.scalar_one_or_none() async def list_filtered( self, tenant_id: UUID, *, offset: int = 0, limit: int = 20, spec: DispatchJobListSpec | None = None, ) -> Sequence[DispatchJob]: stmt = select(self.model).where( self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False), ) if spec is not None: stmt = spec.apply(stmt) else: stmt = stmt.order_by(self.model.created_at.desc()) stmt = stmt.offset(offset).limit(limit) result = await self.session.execute(stmt) return result.scalars().all() async def count_filtered( self, tenant_id: UUID, *, spec: DispatchJobListSpec | None = None ) -> int: stmt = select(func.count()).select_from(self.model).where( self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False), ) if spec is not None: clauses = spec.filter_clauses() if clauses: stmt = stmt.where(*clauses) result = await self.session.execute(stmt) return int(result.scalar_one()) class JobAssignmentRepository(TenantBaseRepository[JobAssignment]): model = JobAssignment async def list_filtered( self, tenant_id: UUID, *, offset: int = 0, limit: int = 20, spec: JobAssignmentListSpec | None = None, ) -> Sequence[JobAssignment]: stmt = select(self.model).where( self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False), ) if spec is not None: stmt = spec.apply(stmt) else: stmt = stmt.order_by(self.model.created_at.desc()) stmt = stmt.offset(offset).limit(limit) result = await self.session.execute(stmt) return result.scalars().all() async def count_filtered( self, tenant_id: UUID, *, spec: JobAssignmentListSpec | None = None ) -> int: stmt = select(func.count()).select_from(self.model).where( self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False), ) if spec is not None: clauses = spec.filter_clauses() if clauses: stmt = stmt.where(*clauses) result = await self.session.execute(stmt) return int(result.scalar_one()) async def list_for_job( self, tenant_id: UUID, dispatch_job_id: UUID ) -> Sequence[JobAssignment]: stmt = select(self.model).where( self.model.tenant_id == tenant_id, self.model.dispatch_job_id == dispatch_job_id, self.model.is_deleted.is_(False), ) result = await self.session.execute(stmt) return result.scalars().all()