Support gacha log rank

This commit is contained in:
xtaodada 2024-09-12 16:18:05 +08:00
parent 42ce49e834
commit e060fcac75
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
5 changed files with 226 additions and 0 deletions

View File

@ -0,0 +1 @@
"""Gacha Log Rank Service"""

View File

@ -0,0 +1,48 @@
from typing import TYPE_CHECKING
from gram_core.base_service import BaseService
from gram_core.dependence.redisdb import RedisDB
__all__ = ("GachaLogRankCache",)
if TYPE_CHECKING:
from gram_core.services.gacha_log_rank.models import GachaLogTypeEnum, GachaLogQueryTypeEnum
class GachaLogRankCache(BaseService.Component):
def __init__(self, redis: RedisDB):
self.client = redis.client
self.qname = "gacha_log_ranks"
def get_key(self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum") -> str:
return f"{self.qname}:{rank_type.value}:{query_type.value}"
async def remove_all(self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum") -> bool:
key = self.get_key(rank_type, query_type)
return await self.client.delete(key)
async def add(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", player_id: int, score: int
) -> bool:
key = self.get_key(rank_type, query_type)
return await self.client.zadd(key, {player_id: score})
async def get_ranks(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", limit: int, desc: bool
):
"""获取排行榜,默认由高到低排序"""
key = self.get_key(rank_type, query_type)
return await self.client.zrange(key, 0, limit - 1, withscores=True, desc=desc)
async def get_ranks_length(self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum"):
"""获取排行榜长度"""
key = self.get_key(rank_type, query_type)
return await self.client.zcard(key)
async def get_rank_by_player_id(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", player_id: int, desc: bool
):
"""获取玩家在排行榜中的排名,默认由高到低排序"""
key = self.get_key(rank_type, query_type)
func = self.client.zrevrank if desc else self.client.zrank
return await func(key, player_id)

View File

@ -0,0 +1,56 @@
import enum
from datetime import datetime
from typing import Optional, Dict, Any
from sqlalchemy import func, BigInteger, JSON
from sqlmodel import Column, DateTime, Enum, Field, SQLModel, Integer
__all__ = ("GachaLogRank", "GachaLogTypeEnum", "GachaLogQueryTypeEnum")
class GachaLogTypeEnum(int, enum.Enum):
CHARACTER = 0 # 角色
WEAPON = 1 # 武器
DEFAULT = 2 # 常驻
DEFAULT_WEAPON = 3 # 常驻武器
HUN = 4 # 集录
PET = 5 # 邦布
class GachaLogQueryTypeEnum(str, enum.Enum):
TOTAL = "score_1"
FIVE_STAR_AVG = "score_2"
UP_STAR_AVG = "score_3"
NO_WARP = "score_4"
class GachaLogRank(SQLModel, table=True):
__tablename__ = "gacha_log_rank"
__table_args__ = dict(mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci")
id: Optional[int] = Field(default=None, sa_column=Column(Integer(), primary_key=True, autoincrement=True))
player_id: int = Field(sa_column=Column(BigInteger(), primary_key=True))
type: GachaLogTypeEnum = Field(sa_column=Column(Enum(GachaLogTypeEnum), primary_key=True))
score_1: int = Field(sa_column=Column(BigInteger(), default=0))
"""总抽数"""
score_2: int = Field(sa_column=Column(BigInteger(), default=0))
"""五星平均"""
score_3: int = Field(sa_column=Column(BigInteger(), default=0))
"""up 平均"""
score_4: int = Field(sa_column=Column(BigInteger(), default=0))
"""小保底不歪概率"""
score_5: int = Field(sa_column=Column(BigInteger(), default=0))
"""保留字段"""
data: Optional[Dict[str, Any]] = Field(sa_column=Column(JSON))
time_created: Optional[datetime] = Field(
sa_column=Column(DateTime, server_default=func.now()) # pylint: disable=E1102
)
time_updated: Optional[datetime] = Field(sa_column=Column(DateTime, onupdate=func.now())) # pylint: disable=E1102
def update_by_new(self, new_ins: "GachaLogRank"):
self.score_1 = new_ins.score_1
self.score_2 = new_ins.score_2
self.score_3 = new_ins.score_3
self.score_4 = new_ins.score_4
self.score_5 = new_ins.score_5
self.data = new_ins.data
self.time_updated = datetime.now()

View File

@ -0,0 +1,54 @@
from typing import List, Optional
from sqlmodel import col, select
from sqlmodel.ext.asyncio.session import AsyncSession
from gram_core.base_service import BaseService
from gram_core.dependence.database import Database
from gram_core.services.gacha_log_rank.models import GachaLogRank, GachaLogTypeEnum, GachaLogQueryTypeEnum
__all__ = ("GachaLogRankRepository",)
class GachaLogRankRepository(BaseService.Component):
def __init__(self, database: Database):
self.engine = database.engine
async def add(self, rank: GachaLogRank):
async with AsyncSession(self.engine) as session:
session.add(rank)
await session.commit()
async def update(self, rank: GachaLogRank) -> GachaLogRank:
async with AsyncSession(self.engine) as session:
session.add(rank)
await session.commit()
await session.refresh(rank)
return rank
async def remove(self, rank: GachaLogRank):
async with AsyncSession(self.engine) as session:
await session.delete(rank)
await session.commit()
async def get_all(self) -> List[GachaLogRank]:
async with AsyncSession(self.engine) as session:
statement = select(GachaLogRank)
results = await session.exec(statement)
return results.all()
async def get_all_by_player_ids(self, rank_type: "GachaLogTypeEnum", ids: List[int]) -> List[GachaLogRank]:
async with AsyncSession(self.engine) as session:
statement = (
select(GachaLogRank).where(col(GachaLogRank.player_id).in_(ids)).where(GachaLogRank.type == rank_type)
)
results = await session.exec(statement)
return results.all()
async def get_by_player_id(self, player_id: int, rank_type: Optional[GachaLogTypeEnum]) -> List[GachaLogRank]:
async with AsyncSession(self.engine) as session:
statement = select(GachaLogRank).where(GachaLogRank.player_id == player_id)
if rank_type:
statement = statement.where(GachaLogRank.type == rank_type)
results = await session.exec(statement)
return results.all()

View File

@ -0,0 +1,67 @@
from typing import List, Optional
from gram_core.base_service import BaseService
from gram_core.services.gacha_log_rank.cache import GachaLogRankCache
from gram_core.services.gacha_log_rank.models import GachaLogRank, GachaLogTypeEnum, GachaLogQueryTypeEnum
from gram_core.services.gacha_log_rank.repositories import GachaLogRankRepository
__all__ = ("GachaLogRankService",)
class GachaLogRankService(BaseService):
def __init__(
self,
gacha_log_rank_repository: GachaLogRankRepository,
gacha_log_rank_cache: GachaLogRankCache,
):
self._repository = gacha_log_rank_repository
self._cache = gacha_log_rank_cache
async def del_all_cache_by_type(self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum") -> bool:
return await self._cache.remove_all(rank_type, query_type)
async def add_cache(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", player_id: int, score: int
) -> bool:
return await self._cache.add(rank_type, query_type, player_id, score)
async def get_ranks_cache(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", limit: int = 20, desc: bool = True
):
"""获取排行榜,默认由高到低排序"""
return await self._cache.get_ranks(rank_type, query_type, limit, desc)
async def get_ranks_length_cache(self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum"):
"""获取排行榜长度"""
return await self._cache.get_ranks_length(rank_type, query_type)
async def get_rank_by_player_id_cache(
self, rank_type: "GachaLogTypeEnum", query_type: "GachaLogQueryTypeEnum", player_id: int, desc: bool = True
):
"""获取玩家在排行榜中的排名,默认由高到低排序"""
return await self._cache.get_rank_by_player_id(rank_type, query_type, player_id, desc)
async def update_cache(self, rank: GachaLogRank):
for type_str in GachaLogQueryTypeEnum:
type_str: "GachaLogQueryTypeEnum"
score = getattr(rank, type_str.value)
if score:
await self.add_cache(rank.type, type_str, rank.player_id, score)
async def add(self, rank: GachaLogRank):
await self.update_cache(rank)
req = await self._repository.add(rank)
return req
async def update(self, rank: GachaLogRank) -> GachaLogRank:
await self.update_cache(rank)
req = await self._repository.update(rank)
return req
async def get_ranks_by_ids(self, rank_type: "GachaLogTypeEnum", ranks_ids: List[int]) -> List[GachaLogRank]:
return await self._repository.get_all_by_player_ids(rank_type, ranks_ids)
async def get_rank_by_user_id(
self, user_id: int, rank_type: Optional["GachaLogTypeEnum"] = None
) -> List[GachaLogRank]:
return await self._repository.get_by_player_id(user_id, rank_type)