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:
2025-12-22 18:29:14 +08:00
parent 47a4756227
commit a5efda9c23
44 changed files with 4306 additions and 497 deletions

View File

@@ -1,32 +1,96 @@
from typing import Optional, TYPE_CHECKING
from enum import StrEnum
from typing import TYPE_CHECKING
from uuid import UUID
from datetime import datetime
from sqlmodel import Field, Relationship, CheckConstraint
from sqlmodel import Field, Relationship, CheckConstraint, Index
from .base import TableBase
from .base import SQLModelBase
from .mixin import TableBaseMixin
if TYPE_CHECKING:
from .user import User
from .download import Download
class Task(TableBase, table=True):
class TaskStatus(StrEnum):
"""任务状态枚举"""
QUEUED = "queued"
"""排队中"""
RUNNING = "running"
"""处理中"""
COMPLETED = "completed"
"""已完成"""
ERROR = "error"
"""错误"""
class TaskType(StrEnum):
"""任务类型枚举"""
# [TODO] 补充具体任务类型
pass
class TaskPropsBase(SQLModelBase):
"""任务属性基础模型"""
source_path: str | None = None
"""源路径"""
dest_path: str | None = None
"""目标路径"""
file_ids: str | None = None
"""文件ID列表逗号分隔"""
# [TODO] 根据业务需求补充更多字段
class TaskProps(TaskPropsBase, TableBaseMixin):
"""任务属性模型与Task一对一关联"""
task_id: int = Field(foreign_key="task.id", primary_key=True)
"""关联的任务ID"""
# 反向关系
task: "Task" = Relationship(back_populates="props")
"""关联的任务"""
class Task(SQLModelBase, TableBaseMixin):
"""任务模型"""
__table_args__ = (
CheckConstraint("progress BETWEEN 0 AND 100", name="ck_task_progress_range"),
Index("ix_task_status", "status"),
Index("ix_task_user_status", "user_id", "status"),
)
status: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务状态: 0=排队中, 1=处理中, 2=完成, 3=错误")
type: int = Field(description="任务类型")
progress: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, description="任务进度 (0-100)")
error: str | None = Field(default=None, description="错误信息")
props: str | None = Field(default=None, description="任务属性 (JSON格式)")
status: TaskStatus = Field(default=TaskStatus.QUEUED, sa_column_kwargs={"server_default": "'queued'"})
"""任务状态"""
type: int = Field(default=0, sa_column_kwargs={"server_default": "0"})
"""任务类型 [TODO] 待定义枚举"""
progress: int = Field(default=0, sa_column_kwargs={"server_default": "0"}, ge=0, le=100)
"""任务进度0-100"""
error: str | None = Field(default=None)
"""错误信息"""
# 外键
user_id: UUID = Field(foreign_key="user.id", index=True, description="所属用户UUID")
user_id: UUID = Field(foreign_key="user.id", index=True)
"""所属用户UUID"""
# 关系
props: TaskProps | None = Relationship(
back_populates="task",
sa_relationship_kwargs={"uselist": False},
)
"""任务属性"""
user: "User" = Relationship(back_populates="tasks")
downloads: list["Download"] = Relationship(back_populates="task")
"""所属用户"""
downloads: list["Download"] = Relationship(back_populates="task")
"""关联的下载任务"""