Compare commits

...

3 Commits
1.0.3 ... 1.0.4

Author SHA1 Message Date
03d34c5572 🔖 1.0.4 2024-05-07 17:22:46 +08:00
04b480ef52 🗃️ HistoricalData 添加 user_unique_identifier 字段 2024-05-07 17:21:52 +08:00
5563b01937 Revert " 为使用了 alias 的 pydantic model 设置 populate_by_name"
This reverts commit 17690e673f.
2024-05-07 08:51:55 +08:00
8 changed files with 110 additions and 64 deletions

View File

@@ -0,0 +1,103 @@
"""Add user_unique_identifier field to HistoricalData
迁移 ID: b7fbdafc339a
父迁移: 8a91210ce14d
创建时间: 2024-05-07 16:55:29.527215
"""
from __future__ import annotations
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
from nonebot.log import logger
revision: str = 'b7fbdafc339a'
down_revision: str | Sequence[str] | None = '8a91210ce14d'
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade(name: str = '') -> None:
if name:
return
from nonebot_plugin_tetris_stats.version import __version__
if __version__ != '1.0.4':
logger.critical('本迁移需要1.0.4版本, 请先锁定版本至1.0.4版本再执行本迁移')
raise RuntimeError('本迁移需要1.0.4版本, 请先锁定版本至1.0.4版本再执行本迁移')
from nonebot.compat import type_validate_json
from pydantic import ValidationError
from rich.progress import (
BarColumn,
MofNCompleteColumn,
Progress,
TaskProgressColumn,
TextColumn,
TimeRemainingColumn,
)
from sqlalchemy import select
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from nonebot_plugin_tetris_stats.game_data_processor.schemas import BaseUser
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
batch_op.add_column(sa.Column('user_unique_identifier', sa.String(length=32), nullable=True))
batch_op.create_index(
batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_user_unique_identifier'),
['user_unique_identifier'],
unique=False,
)
Base = automap_base() # noqa: N806
connection = op.get_bind()
Base.prepare(autoload_with=connection)
HistoricalData = Base.classes.nonebot_plugin_tetris_stats_historicaldata # noqa: N806
models: list[type[BaseUser]] = BaseUser.__subclasses__()
def json_to_model(value: str) -> BaseUser:
for i in models:
try:
return type_validate_json(i, value)
except ValidationError: # noqa: PERF203
...
raise ValueError
with Session(op.get_bind()) as session:
count = session.query(HistoricalData).count()
with Progress(
TextColumn('[progress.description]{task.description}'),
BarColumn(),
MofNCompleteColumn(),
TaskProgressColumn(),
TimeRemainingColumn(),
) as progress:
task_id = progress.add_task('[cyan]Updateing:', total=count)
for i in range(0, count, 100):
for j in session.scalars(
select(HistoricalData).where(HistoricalData.id > i).order_by(HistoricalData.id).limit(100)
):
model = json_to_model(j.game_user)
try:
j.user_unique_identifier = model.unique_identifier
except ValueError:
session.delete(j)
progress.update(task_id, advance=1)
session.commit()
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
batch_op.alter_column('user_unique_identifier', existing_type=sa.VARCHAR(length=32), nullable=False)
logger.success('database upgrade success')
def downgrade(name: str = '') -> None:
if name:
return
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('nonebot_plugin_tetris_stats_historicaldata', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_nonebot_plugin_tetris_stats_historicaldata_user_unique_identifier'))
batch_op.drop_column('user_unique_identifier')
# ### end Alembic commands ###

View File

@@ -70,6 +70,7 @@ class HistoricalData(MappedAsDataclass, Model):
game_platform: Mapped[GameType] = mapped_column(String(32), index=True, init=False) game_platform: Mapped[GameType] = mapped_column(String(32), index=True, init=False)
command_type: Mapped[CommandType] = mapped_column(String(16), index=True, init=False) command_type: Mapped[CommandType] = mapped_column(String(16), index=True, init=False)
command_args: Mapped[list[str]] = mapped_column(JSON, init=False) command_args: Mapped[list[str]] = mapped_column(JSON, init=False)
user_unique_identifier: Mapped[str] = mapped_column(String(32), index=True, init=False)
game_user: Mapped[BaseUser] = mapped_column(PydanticType(get_model=BaseUser.__subclasses__), init=False) game_user: Mapped[BaseUser] = mapped_column(PydanticType(get_model=BaseUser.__subclasses__), init=False)
processed_data: Mapped[BaseProcessedData] = mapped_column( processed_data: Mapped[BaseProcessedData] = mapped_column(
PydanticType(get_model=BaseProcessedData.__subclasses__), init=False PydanticType(get_model=BaseProcessedData.__subclasses__), init=False

View File

@@ -68,6 +68,7 @@ class Processor(ABC):
historical_data.game_platform = self.game_platform historical_data.game_platform = self.game_platform
historical_data.command_type = self.command_type historical_data.command_type = self.command_type
historical_data.command_args = self.command_args historical_data.command_args = self.command_args
historical_data.user_unique_identifier = self.user.unique_identifier
historical_data.game_user = self.user historical_data.game_user = self.user
historical_data.processed_data = self.processed_data historical_data.processed_data = self.processed_data
historical_data.finish_time = finish_time historical_data.finish_time = finish_time

View File

@@ -1,5 +1,4 @@
from nonebot.compat import PYDANTIC_V2 from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
from ..typing import Rank from ..typing import Rank
from .base import FailedModel from .base import FailedModel
@@ -14,12 +13,6 @@ class _User(BaseModel):
supporter: bool supporter: bool
verified: bool verified: bool
country: str | None = None country: str | None = None
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class SuccessModel(BaseSuccessModel): class SuccessModel(BaseSuccessModel):

View File

@@ -1,8 +1,7 @@
from datetime import datetime from datetime import datetime
from typing import Literal from typing import Literal
from nonebot.compat import PYDANTIC_V2 from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
from ..typing import Rank from ..typing import Rank
from .base import FailedModel from .base import FailedModel
@@ -114,12 +113,6 @@ class SuccessModel(BaseSuccessModel):
connections: Connections connections: Connections
friend_count: int | None = None friend_count: int | None = None
distinguishment: Distinguishment | None = None distinguishment: Distinguishment | None = None
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
user: User user: User

View File

@@ -1,7 +1,6 @@
from datetime import datetime from datetime import datetime
from nonebot.compat import PYDANTIC_V2 from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
from .base import FailedModel from .base import FailedModel
from .base import SuccessModel as BaseSuccessModel from .base import SuccessModel as BaseSuccessModel
@@ -67,23 +66,11 @@ class EndContext(BaseModel):
finesse: Finesse finesse: Finesse
final_time: float = Field(..., alias='finalTime') final_time: float = Field(..., alias='finalTime')
gametype: str gametype: str
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class _User(BaseModel): class _User(BaseModel):
id: str = Field(..., alias='_id') id: str = Field(..., alias='_id')
username: str username: str
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class _Record(BaseModel): class _Record(BaseModel):
@@ -93,12 +80,6 @@ class _Record(BaseModel):
user: _User user: _User
ts: datetime ts: datetime
ismulti: bool | None = None ismulti: bool | None = None
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class BaseModeRecord(BaseModel): class BaseModeRecord(BaseModel):
@@ -121,12 +102,6 @@ class SuccessModel(BaseSuccessModel):
sprint: Sprint = Field(..., alias='40l') sprint: Sprint = Field(..., alias='40l')
blitz: Blitz blitz: Blitz
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class Zen(BaseModel): class Zen(BaseModel):
level: int level: int

View File

@@ -1,8 +1,7 @@
from datetime import datetime from datetime import datetime
from typing import Literal from typing import Literal
from nonebot.compat import PYDANTIC_V2 from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field
class SuccessModel(BaseModel): class SuccessModel(BaseModel):
@@ -17,12 +16,6 @@ class SuccessModel(BaseModel):
win: str win: str
lose: str lose: str
score: str score: str
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
class UserDataTotalItem(BaseModel): class UserDataTotalItem(BaseModel):
time_map: str = Field(..., alias='timeMap') time_map: str = Field(..., alias='timeMap')
@@ -55,12 +48,6 @@ class SuccessModel(BaseModel):
tspin_no_map: str = Field(..., alias='tspinNoMap') tspin_no_map: str = Field(..., alias='tspinNoMap')
b2b_no_map: str = Field(..., alias='b2bNoMap') b2b_no_map: str = Field(..., alias='b2bNoMap')
perfect_clear_no_map: str = Field(..., alias='perfectClearNoMap') perfect_clear_no_map: str = Field(..., alias='perfectClearNoMap')
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
teaid: str = Field(..., alias='teaId') teaid: str = Field(..., alias='teaId')
name: str name: str
@@ -85,13 +72,6 @@ class SuccessModel(BaseModel):
register_date: datetime = Field(..., alias='registerDate') register_date: datetime = Field(..., alias='registerDate')
last_login_date: datetime = Field(..., alias='lastLoginDate') last_login_date: datetime = Field(..., alias='lastLoginDate')
if PYDANTIC_V2:
model_config = ConfigDict(populate_by_name=True)
else:
class Config:
allow_population_by_field_name = True
code: int code: int
success: Literal[True] success: Literal[True]
data: Data data: Data

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = 'nonebot-plugin-tetris-stats' name = 'nonebot-plugin-tetris-stats'
version = '1.0.3' version = '1.0.4'
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件' description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
authors = ['scdhh <wallfjjd@gmail.com>'] authors = ['scdhh <wallfjjd@gmail.com>']
readme = 'README.md' readme = 'README.md'