This commit is contained in:
咕谷酱
2025-08-22 00:07:19 +08:00
parent bade8658ed
commit 80d4237c5d
22 changed files with 423 additions and 356 deletions

View File

@@ -8,7 +8,7 @@ from app.models.score import GameMode
from .lazer_user import BASE_INCLUDES, User, UserResp
from pydantic import BaseModel, field_validator, model_validator
from sqlalchemy import Boolean, JSON, Column, DateTime, Text
from sqlalchemy import JSON, Boolean, Column, DateTime, Text
from sqlalchemy.ext.asyncio import AsyncAttrs
from sqlmodel import Field, Relationship, SQLModel, col, exists, func, select
from sqlmodel.ext.asyncio.session import AsyncSession
@@ -205,7 +205,18 @@ class BeatmapsetResp(BeatmapsetBase):
favourite_count: int = 0
recent_favourites: list[UserResp] = Field(default_factory=list)
@field_validator('nsfw', 'spotlight', 'video', 'can_be_hyped', 'discussion_locked', 'storyboard', 'discussion_enabled', 'is_scoreable', 'has_favourited', mode='before')
@field_validator(
"nsfw",
"spotlight",
"video",
"can_be_hyped",
"discussion_locked",
"storyboard",
"discussion_enabled",
"is_scoreable",
"has_favourited",
mode="before",
)
@classmethod
def validate_bool_fields(cls, v):
"""将整数 0/1 转换为布尔值,处理数据库中的布尔字段"""

View File

@@ -2,13 +2,16 @@
数据库字段类型工具
提供处理数据库和 Pydantic 之间类型转换的工具
"""
from typing import Any, Union
from typing import Any
from pydantic import field_validator
from sqlalchemy import Boolean
def bool_field_validator(field_name: str):
"""为特定布尔字段创建验证器,处理数据库中的 0/1 整数"""
@field_validator(field_name, mode="before")
@classmethod
def validate_bool_field(cls, v: Any) -> bool:
@@ -16,20 +19,21 @@ def bool_field_validator(field_name: str):
if isinstance(v, int):
return bool(v)
return v
return validate_bool_field
def create_bool_field(**kwargs):
"""创建一个带有正确 SQLAlchemy 列定义的布尔字段"""
from sqlmodel import Field, Column
from sqlmodel import Column, Field
# 如果没有指定 sa_column则使用 Boolean 类型
if 'sa_column' not in kwargs:
if "sa_column" not in kwargs:
# 处理 index 参数
index = kwargs.pop('index', False)
index = kwargs.pop("index", False)
if index:
kwargs['sa_column'] = Column(Boolean, index=True)
kwargs["sa_column"] = Column(Boolean, index=True)
else:
kwargs['sa_column'] = Column(Boolean)
kwargs["sa_column"] = Column(Boolean)
return Field(**kwargs)

View File

@@ -136,7 +136,7 @@ class UserBase(UTCBaseModel, SQLModel):
is_qat: bool = False
is_bng: bool = False
@field_validator('playmode', mode='before')
@field_validator("playmode", mode="before")
@classmethod
def validate_playmode(cls, v):
"""将字符串转换为 GameMode 枚举"""

View File

@@ -100,7 +100,7 @@ class ScoreBase(AsyncAttrs, SQLModel, UTCBaseModel):
sa_column=Column(JSON), default_factory=dict
)
@field_validator('maximum_statistics', mode='before')
@field_validator("maximum_statistics", mode="before")
@classmethod
def validate_maximum_statistics(cls, v):
"""处理 maximum_statistics 字段中的字符串键,转换为 HitResult 枚举"""
@@ -151,7 +151,7 @@ class Score(ScoreBase, table=True):
gamemode: GameMode = Field(index=True)
pinned_order: int = Field(default=0, exclude=True)
@field_validator('gamemode', mode='before')
@field_validator("gamemode", mode="before")
@classmethod
def validate_gamemode(cls, v):
"""将字符串转换为 GameMode 枚举"""
@@ -209,7 +209,16 @@ class ScoreResp(ScoreBase):
ranked: bool = False
current_user_attributes: CurrentUserAttributes | None = None
@field_validator('has_replay', 'passed', 'preserve', 'is_perfect_combo', 'legacy_perfect', 'processed', 'ranked', mode='before')
@field_validator(
"has_replay",
"passed",
"preserve",
"is_perfect_combo",
"legacy_perfect",
"processed",
"ranked",
mode="before",
)
@classmethod
def validate_bool_fields(cls, v):
"""将整数 0/1 转换为布尔值,处理数据库中的布尔字段"""
@@ -217,7 +226,7 @@ class ScoreResp(ScoreBase):
return bool(v)
return v
@field_validator('statistics', 'maximum_statistics', mode='before')
@field_validator("statistics", "maximum_statistics", mode="before")
@classmethod
def validate_statistics_fields(cls, v):
"""处理统计字段中的字符串键,转换为 HitResult 枚举"""

View File

@@ -44,7 +44,7 @@ class UserStatisticsBase(SQLModel):
replays_watched_by_others: int = Field(default=0)
is_ranked: bool = Field(default=True)
@field_validator('mode', mode='before')
@field_validator("mode", mode="before")
@classmethod
def validate_mode(cls, v):
"""将字符串转换为 GameMode 枚举"""