867e2aa552
# Conflicts: # server/infrastructure/database/setting_repo.py
80 lines
2.8 KiB
Python
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 |