feat(mixin): add TableBaseMixin and UUIDTableBaseMixin for async CRUD operations
- Implemented TableBaseMixin providing generic CRUD methods and automatic timestamp management. - Introduced UUIDTableBaseMixin for models using UUID as primary keys. - Added ListResponse for standardized paginated responses. - Created TimeFilterRequest and PaginationRequest for filtering and pagination parameters. - Enhanced get_with_count method to return both item list and total count. - Included validation for time filter parameters in TimeFilterRequest. - Improved documentation and usage examples throughout the code.
This commit is contained in:
@@ -1,46 +1,176 @@
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from enum import StrEnum
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import UUID
|
||||
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint
|
||||
from sqlmodel import Field, Relationship, UniqueConstraint, Index
|
||||
|
||||
from .base import SQLModelBase
|
||||
from .mixin import UUIDTableBaseMixin, TableBaseMixin
|
||||
|
||||
|
||||
class DownloadStatus(StrEnum):
|
||||
"""下载状态枚举"""
|
||||
RUNNING = "running"
|
||||
"""进行中"""
|
||||
COMPLETED = "completed"
|
||||
"""已完成"""
|
||||
ERROR = "error"
|
||||
"""错误"""
|
||||
|
||||
|
||||
class DownloadType(StrEnum):
|
||||
"""下载类型枚举"""
|
||||
# [TODO] 补充具体下载类型
|
||||
pass
|
||||
|
||||
from .base import SQLModelBase, UUIDTableBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
from .task import Task
|
||||
from .node import Node
|
||||
|
||||
|
||||
# ==================== Aria2 信息模型 ====================
|
||||
|
||||
class DownloadAria2InfoBase(SQLModelBase):
|
||||
"""Aria2下载信息基础模型"""
|
||||
|
||||
info_hash: str | None = Field(default=None, max_length=40)
|
||||
"""InfoHash(BT种子)"""
|
||||
|
||||
piece_length: int = 0
|
||||
"""分片大小"""
|
||||
|
||||
num_pieces: int = 0
|
||||
"""分片数量"""
|
||||
|
||||
num_seeders: int = 0
|
||||
"""做种人数"""
|
||||
|
||||
connections: int = 0
|
||||
"""连接数"""
|
||||
|
||||
upload_speed: int = 0
|
||||
"""上传速度(bytes/s)"""
|
||||
|
||||
upload_length: int = 0
|
||||
"""已上传大小(字节)"""
|
||||
|
||||
error_code: str | None = None
|
||||
"""错误代码"""
|
||||
|
||||
error_message: str | None = None
|
||||
"""错误信息"""
|
||||
|
||||
|
||||
class DownloadAria2Info(DownloadAria2InfoBase, SQLModelBase, table=True):
|
||||
"""Aria2下载信息模型(与Download一对一关联)"""
|
||||
|
||||
download_id: UUID = Field(foreign_key="download.id", primary_key=True)
|
||||
"""关联的下载任务UUID"""
|
||||
|
||||
# 反向关系
|
||||
download: "Download" = Relationship(back_populates="aria2_info")
|
||||
"""关联的下载任务"""
|
||||
|
||||
|
||||
class DownloadAria2File(SQLModelBase, TableBaseMixin):
|
||||
"""Aria2下载文件列表(与Download一对多关联)"""
|
||||
|
||||
download_id: UUID = Field(foreign_key="download.id", index=True)
|
||||
"""关联的下载任务UUID"""
|
||||
|
||||
file_index: int = Field(ge=1)
|
||||
"""文件索引(从1开始)"""
|
||||
|
||||
path: str
|
||||
"""文件路径"""
|
||||
|
||||
length: int = 0
|
||||
"""文件大小(字节)"""
|
||||
|
||||
completed_length: int = 0
|
||||
"""已完成大小(字节)"""
|
||||
|
||||
is_selected: bool = True
|
||||
"""是否选中下载"""
|
||||
|
||||
# 反向关系
|
||||
download: "Download" = Relationship(back_populates="aria2_files")
|
||||
"""关联的下载任务"""
|
||||
|
||||
|
||||
# ==================== 主模型 ====================
|
||||
|
||||
class DownloadBase(SQLModelBase):
|
||||
pass
|
||||
|
||||
class Download(DownloadBase, UUIDTableBase, table=True):
|
||||
class Download(DownloadBase, UUIDTableBaseMixin):
|
||||
"""离线下载任务模型"""
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("node_id", "g_id", name="uq_download_node_gid"),
|
||||
Index("ix_download_status", "status"),
|
||||
Index("ix_download_user_status", "user_id", "status"),
|
||||
)
|
||||
|
||||
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="下载状态: 0=进行中, 1=完成, 2=错误")
|
||||
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务类型")
|
||||
source: str = Field(description="来源URL或标识")
|
||||
total_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="总大小(字节)")
|
||||
downloaded_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="已下载大小(字节)")
|
||||
g_id: str | None = Field(default=None, index=True, description="Aria2 GID")
|
||||
speed: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="下载速度 (bytes/s)")
|
||||
parent: str | None = Field(default=None, description="父任务标识")
|
||||
attrs: str | None = Field(default=None, description="额外属性 (JSON格式)")
|
||||
# attrs 示例: {"gid":"65c5faf38374cc63","status":"removed","totalLength":"0","completedLength":"0","uploadLength":"0","bitfield":"","downloadSpeed":"0","uploadSpeed":"0","infoHash":"ca159db2b1e78f6e95fd972be72251f967f639d4","numSeeders":"0","seeder":"","pieceLength":"16384","numPieces":"0","connections":"0","errorCode":"31","errorMessage":"","followedBy":null,"belongsTo":"","dir":"/data/ccaaDown/aria2/7a208304-9126-46d2-ba47-a6959f236a07","files":[{"index":"1","path":"[METADATA]zh-cn_windows_11_consumer_editions_version_21h2_updated_aug_2022_x64_dvd_a29983d5.iso","length":"0","completedLength":"0","selected":"true","uris":[]}],"bittorrent":{"announceList":[["udp://tracker.opentrackr.org:1337/announce"],["udp://9.rarbg.com:2810/announce"],["udp://tracker.openbittorrent.com:6969/announce"],["https://opentracker.i2p.rocks:443/announce"],["http://tracker.openbittorrent.com:80/announce"],["udp://open.stealth.si:80/announce"],["udp://tracker.torrent.eu.org:451/announce"],["udp://exodus.desync.com:6969/announce"],["udp://tracker.tiny-vps.com:6969/announce"],["udp://tracker.pomf.se:80/announce"],["udp://tracker.moeking.me:6969/announce"],["udp://tracker.dler.org:6969/announce"],["udp://open.demonii.com:1337/announce"],["udp://explodie.org:6969/announce"],["udp://chouchou.top:8080/announce"],["udp://bt.oiyo.tk:6969/announce"],["https://tracker.nanoha.org:443/announce"],["https://tracker.lilithraws.org:443/announce"],["http://tracker3.ctix.cn:8080/announce"],["http://tracker.nucozer-tracker.ml:2710/announce"]],"comment":"","creationDate":0,"mode":"","info":{"name":""}}}
|
||||
error: str | None = Field(default=None, description="错误信息")
|
||||
dst: str = Field(description="目标存储路径")
|
||||
|
||||
status: DownloadStatus = Field(default=DownloadStatus.RUNNING, sa_column_kwargs={"server_default": "'running'"})
|
||||
"""下载状态"""
|
||||
|
||||
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"})
|
||||
"""任务类型 [TODO] 待定义枚举"""
|
||||
|
||||
source: str
|
||||
"""来源URL或标识"""
|
||||
|
||||
total_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"})
|
||||
"""总大小(字节)"""
|
||||
|
||||
downloaded_size: int = Field(default=0, sa_column_kwargs={"server_default": "0"})
|
||||
"""已下载大小(字节)"""
|
||||
|
||||
g_id: str | None = Field(default=None, index=True)
|
||||
"""Aria2 GID"""
|
||||
|
||||
speed: int = Field(default=0, sa_column_kwargs={"server_default": "0"})
|
||||
"""下载速度(bytes/s)"""
|
||||
|
||||
parent: str | None = Field(default=None, max_length=255)
|
||||
"""父任务标识"""
|
||||
|
||||
error: str | None = Field(default=None)
|
||||
"""错误信息"""
|
||||
|
||||
dst: str
|
||||
"""目标存储路径"""
|
||||
|
||||
# 外键
|
||||
user_id: UUID = Field(foreign_key="user.id", index=True, description="所属用户UUID")
|
||||
task_id: int | None = Field(default=None, foreign_key="task.id", index=True, description="关联的任务ID")
|
||||
node_id: int = Field(foreign_key="node.id", index=True, description="执行下载的节点ID")
|
||||
|
||||
user_id: UUID = Field(foreign_key="user.id", index=True)
|
||||
"""所属用户UUID"""
|
||||
|
||||
task_id: int | None = Field(default=None, foreign_key="task.id", index=True)
|
||||
"""关联的任务ID"""
|
||||
|
||||
node_id: int = Field(foreign_key="node.id", index=True)
|
||||
"""执行下载的节点ID"""
|
||||
|
||||
# 关系
|
||||
aria2_info: DownloadAria2Info | None = Relationship(
|
||||
back_populates="download",
|
||||
sa_relationship_kwargs={"uselist": False},
|
||||
)
|
||||
"""Aria2下载信息"""
|
||||
|
||||
aria2_files: list[DownloadAria2File] = Relationship(back_populates="download")
|
||||
"""Aria2文件列表"""
|
||||
|
||||
user: "User" = Relationship(back_populates="downloads")
|
||||
task: Optional["Task"] = Relationship(back_populates="downloads")
|
||||
"""所属用户"""
|
||||
|
||||
task: "Task" = Relationship(back_populates="downloads")
|
||||
"""关联的任务"""
|
||||
|
||||
node: "Node" = Relationship(back_populates="downloads")
|
||||
"""执行下载的节点"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user