Add the experience service with sites through analytics/AI hooks, migrations through 0011, and phase docs/manifests marking the track complete. Co-authored-by: Cursor <cursoragent@cursor.com>
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
"""Tenant-scoped repositories for Phase 11.9."""
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import func, select
|
|
|
|
from app.models.integrations import (
|
|
ExperienceConsumerConnectorDispatch,
|
|
ExperienceConsumerConnectorRegistration,
|
|
ExperienceNotifyDispatch,
|
|
ExperienceWidgetDefinition,
|
|
ExperienceWidgetInstance,
|
|
)
|
|
from app.repositories.base import TenantBaseRepository
|
|
|
|
|
|
class _FilteredRepository:
|
|
async def list_filtered(self, tenant_id, *, offset, limit, spec=None):
|
|
base = select(self.model).where(
|
|
self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False)
|
|
)
|
|
count = select(func.count()).select_from(self.model).where(
|
|
self.model.tenant_id == tenant_id, self.model.is_deleted.is_(False)
|
|
)
|
|
if spec:
|
|
base = spec.apply(base)
|
|
count = count.where(*spec.filter_clauses())
|
|
else:
|
|
base = base.order_by(self.model.created_at.desc())
|
|
total = int((await self.session.execute(count)).scalar_one())
|
|
items = (await self.session.execute(base.offset(offset).limit(limit))).scalars().all()
|
|
return items, total
|
|
|
|
|
|
class ConsumerConnectorRegistrationRepository(
|
|
_FilteredRepository, TenantBaseRepository[ExperienceConsumerConnectorRegistration]
|
|
):
|
|
model = ExperienceConsumerConnectorRegistration
|
|
|
|
|
|
class ConsumerConnectorDispatchRepository(
|
|
_FilteredRepository, TenantBaseRepository[ExperienceConsumerConnectorDispatch]
|
|
):
|
|
model = ExperienceConsumerConnectorDispatch
|
|
|
|
|
|
class WidgetDefinitionRepository(
|
|
_FilteredRepository, TenantBaseRepository[ExperienceWidgetDefinition]
|
|
):
|
|
model = ExperienceWidgetDefinition
|
|
|
|
|
|
class WidgetInstanceRepository(_FilteredRepository, TenantBaseRepository[ExperienceWidgetInstance]):
|
|
model = ExperienceWidgetInstance
|
|
|
|
async def get_by_embed_ref(self, tenant_id: UUID, embed_ref: str):
|
|
stmt = select(self.model).where(
|
|
self.model.tenant_id == tenant_id,
|
|
self.model.embed_ref == embed_ref,
|
|
self.model.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class NotifyDispatchRepository(_FilteredRepository, TenantBaseRepository[ExperienceNotifyDispatch]):
|
|
model = ExperienceNotifyDispatch
|