Files
Nexus/server/infrastructure/database/sync_log_repo.py
T
Your Name 867e2aa552 Merge branch 'claude/condescending-ishizaka-3cff3a'
# Conflicts:
#	server/infrastructure/database/setting_repo.py
2026-05-26 21:58:38 +08:00

80 lines
2.8 KiB
Python

"""Nexus — SyncLog Repository (Async SQLAlchemy implementation)"""
from typing import Optional, List, Tuple
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from server.domain.models import SyncLog, Server
class SyncLogRepositoryImpl:
"""Async SQLAlchemy implementation of SyncLog data access"""
def __init__(self, session: AsyncSession):
self.session = session
async def get_by_server_id(self, server_id: int, limit: int = 50) -> List[SyncLog]:
result = await self.session.execute(
select(SyncLog)
.where(SyncLog.server_id == server_id)
.order_by(SyncLog.started_at.desc())
.limit(limit)
)
return list(result.scalars().all())
async def get_all_paginated(
self,
server_id: Optional[int] = None,
status: Optional[str] = None,
sync_mode: Optional[str] = None,
trigger_type: Optional[str] = None,
offset: int = 0,
limit: int = 50,
) -> Tuple[list, int]:
"""Global sync log list with filters + server name join + total count."""
filters = []
if server_id:
filters.append(SyncLog.server_id == server_id)
if status:
filters.append(SyncLog.status == status)
if sync_mode:
filters.append(SyncLog.sync_mode == sync_mode)
if trigger_type:
filters.append(SyncLog.trigger_type == trigger_type)
# Count
count_stmt = select(func.count(SyncLog.id))
if filters:
count_stmt = count_stmt.where(*filters)
total = int((await self.session.execute(count_stmt)).scalar() or 0)
# Data (with server name join)
data_stmt = (
select(SyncLog, Server.name.label("server_name"))
.join(Server, SyncLog.server_id == Server.id, isouter=True)
.order_by(SyncLog.started_at.desc())
.offset(offset)
.limit(limit)
)
if filters:
data_stmt = data_stmt.where(*filters)
rows = (await self.session.execute(data_stmt)).all()
return rows, total
async def create(self, log: SyncLog) -> SyncLog:
self.session.add(log)
await self.session.commit()
return log
# Allowed fields for update_status — prevents arbitrary field injection via **kwargs
SYNC_LOG_UPDATABLE_FIELDS = {"finished_at", "duration_seconds", "error_message", "diff_summary", "status"}
async def update_status(self, id: int, status: str, **kwargs) -> Optional[SyncLog]:
log = await self.session.get(SyncLog, id)
if log:
log.status = status
for key, value in kwargs.items():
if key in self.SYNC_LOG_UPDATABLE_FIELDS:
setattr(log, key, value)
await self.session.commit()
return log