"""Campaign application repositories — Phase 7.4.""" from __future__ import annotations from uuid import UUID from sqlalchemy import func, select from app.models.campaigns import CampaignApplication from app.repositories.base import TenantBaseRepository class CampaignApplicationRepository(TenantBaseRepository[CampaignApplication]): model = CampaignApplication async def get_by_idempotency( self, tenant_id: UUID, idempotency_key: str | None ) -> CampaignApplication | None: if not idempotency_key: return None stmt = select(CampaignApplication).where( CampaignApplication.tenant_id == tenant_id, CampaignApplication.idempotency_key == idempotency_key, ) result = await self.session.execute(stmt) return result.scalar_one_or_none() async def count_for_member( self, tenant_id: UUID, campaign_id: UUID, member_id: UUID, *, exclude_statuses: tuple = (), ) -> int: clauses = [ CampaignApplication.tenant_id == tenant_id, CampaignApplication.campaign_id == campaign_id, CampaignApplication.member_id == member_id, ] if exclude_statuses: clauses.append(CampaignApplication.status.notin_(exclude_statuses)) stmt = select(func.count()).select_from(CampaignApplication).where(*clauses) result = await self.session.execute(stmt) return int(result.scalar_one()) async def list_for_campaign( self, tenant_id: UUID, campaign_id: UUID, *, offset: int = 0, limit: int = 50, ): stmt = ( select(CampaignApplication) .where( CampaignApplication.tenant_id == tenant_id, CampaignApplication.campaign_id == campaign_id, ) .order_by(CampaignApplication.created_at.desc()) .offset(offset) .limit(limit) ) result = await self.session.execute(stmt) return result.scalars().all() async def count_for_campaign(self, tenant_id: UUID, campaign_id: UUID) -> int: stmt = ( select(func.count()) .select_from(CampaignApplication) .where( CampaignApplication.tenant_id == tenant_id, CampaignApplication.campaign_id == campaign_id, ) ) result = await self.session.execute(stmt) return int(result.scalar_one())