"""审计事件数据访问。""" from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.models.safety import AuditEvent async def add_audit_event(session: AsyncSession, event: AuditEvent) -> AuditEvent: session.add(event) await session.flush() return event async def list_audit_events( session: AsyncSession, *, pivot: str | None = None, character_id: str | None = None, page: int = 1, page_size: int = 50, ) -> tuple[list[AuditEvent], int]: """起居注时间河:按 created_at 倒序,可选按枢/人物过滤,返回 (条目, 总数)。""" conditions = [] if pivot: conditions.append(AuditEvent.pivot == pivot) if character_id: conditions.append(AuditEvent.character_id == character_id) total_result = await session.execute( select(func.count()).select_from(AuditEvent).where(*conditions) ) total = int(total_result.scalar_one()) result = await session.execute( select(AuditEvent) .where(*conditions) .order_by(AuditEvent.created_at.desc()) .offset((page - 1) * page_size) .limit(page_size) ) return list(result.scalars().all()), total async def list_audit_events_by_trace(session: AsyncSession, trace_id: str) -> list[AuditEvent]: """链路追踪:按 trace_id 查询审计事件,按 created_at 升序(与运行事件归并排序)。""" result = await session.execute( select(AuditEvent) .where(AuditEvent.trace_id == trace_id) .order_by(AuditEvent.created_at.asc()) ) return list(result.scalars().all()) async def summarize_by_trace(session: AsyncSession): """GROUP BY trace_id:(trace_id, 计数, 最近时间),仅 trace_id 非空。供链路追踪列表聚合。""" result = await session.execute( select(AuditEvent.trace_id, func.count(), func.max(AuditEvent.created_at)) .where(AuditEvent.trace_id.is_not(None)) .group_by(AuditEvent.trace_id) ) return [(row[0], int(row[1]), row[2]) for row in result.all()]