Files
Nexus/server/infrastructure/database/server_repo.py
T
Your Name 82c297776a feat: 推送页面 5 项迭代 — WS实时进度 + 分组选择 + 历史增强 + 文件操作 + 推送校验
F1: broadcast_sync_progress() + batch_id + 前端WS逐台更新
F2: get_paginated() platform_id/node_id + /categories端点 + 筛选下拉框
F4: _sync_log_to_dict() 补全字段 + diff_summary捕获 + 可展开详情面板
F7: /local-file-ops端点 + 文件管理器删除/重命名
F8: /verify端点 md5sum对比 + 推送后校验UI

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 21:01:27 +08:00

105 lines
3.6 KiB
Python

"""Nexus — Server Repository (Async SQLAlchemy implementation)
Concrete implementation of ServerRepository protocol.
"""
from datetime import datetime, timezone
from typing import Optional, List, Tuple
from sqlalchemy import select, update, delete, func
from sqlalchemy.ext.asyncio import AsyncSession
from server.domain.models import Server
class ServerRepositoryImpl:
"""Async SQLAlchemy implementation of Server data access"""
def __init__(self, session: AsyncSession):
self.session = session
async def get_by_id(self, id: int) -> Optional[Server]:
result = await self.session.execute(select(Server).where(Server.id == id))
return result.scalar_one_or_none()
async def get_all(self) -> List[Server]:
result = await self.session.execute(select(Server).order_by(Server.id))
return list(result.scalars().all())
async def get_paginated(
self,
category: Optional[str] = None,
platform_id: Optional[int] = None,
node_id: Optional[int] = None,
offset: int = 0,
limit: int = 50,
) -> Tuple[List[Server], int]:
"""Get paginated server list with total count.
Returns (servers, total_count) — DB-level pagination for 2000+ servers.
"""
filters = []
if category:
filters.append(Server.category == category)
if platform_id:
filters.append(Server.platform_id == platform_id)
if node_id:
filters.append(Server.node_id == node_id)
# Count query
count_query = select(func.count(Server.id))
for f in filters:
count_query = count_query.where(f)
count_result = await self.session.execute(count_query)
total = count_result.scalar_one() or 0
# Paginated data query
data_query = select(Server)
for f in filters:
data_query = data_query.where(f)
data_query = data_query.order_by(Server.id).offset(offset).limit(limit)
result = await self.session.execute(data_query)
servers = list(result.scalars().all())
return servers, total
async def get_by_category(self, category: str) -> List[Server]:
result = await self.session.execute(
select(Server).where(Server.category == category).order_by(Server.id)
)
return list(result.scalars().all())
async def get_online(self) -> List[Server]:
result = await self.session.execute(
select(Server).where(Server.is_online == True).order_by(Server.id)
)
return list(result.scalars().all())
async def create(self, server: Server) -> Server:
self.session.add(server)
await self.session.commit()
return server
async def update(self, server: Server) -> Server:
await self.session.commit()
return server
async def delete(self, id: int) -> bool:
server = await self.get_by_id(id)
if server:
await self.session.delete(server)
await self.session.commit()
return True
return False
async def update_heartbeat(self, id: int, is_online: bool, system_info: str, agent_version: str) -> None:
"""Update server online status from Agent heartbeat"""
await self.session.execute(
update(Server)
.where(Server.id == id)
.values(
is_online=is_online,
last_heartbeat=datetime.now(timezone.utc),
system_info=system_info,
agent_version=agent_version,
)
)
await self.session.commit()