TorbatYar/backend/services/experience/app/repositories/analytics.py
Mortezakoohjani 203671a7bf feat(experience): ship Experience Platform phases 11.0-11.10
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>
2026-07-27 11:43:10 +03:30

50 lines
1.7 KiB
Python

"""Tenant-scoped repositories for Phase 11.10 analytics."""
from uuid import UUID
from sqlalchemy import func, select
from app.models.analytics import (
ExperienceAnalyticsReportDefinition,
ExperienceAnalyticsSnapshot,
)
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 AnalyticsReportDefinitionRepository(
_FilteredRepository, TenantBaseRepository[ExperienceAnalyticsReportDefinition]
):
model = ExperienceAnalyticsReportDefinition
async def get_by_code(self, tenant_id: UUID, code: str):
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()
class AnalyticsSnapshotRepository(
_FilteredRepository, TenantBaseRepository[ExperienceAnalyticsSnapshot]
):
model = ExperienceAnalyticsSnapshot