61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""审计事件数据访问。"""
|
||
|
||
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()]
|