178 lines
6.5 KiB
Python
178 lines
6.5 KiB
Python
|
from typing import Optional, Dict, List
|
||
|
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, case
|
||
|
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean
|
||
|
from sqlalchemy.schema import ForeignKey
|
||
|
from sqlalchemy.sql import func, select, update, delete
|
||
|
from sqlalchemy.engine import Row
|
||
|
from sqlalchemy.dialects.mysql import insert
|
||
|
|
||
|
from core.data.schema import BaseData, metadata
|
||
|
|
||
|
item = Table(
|
||
|
"wacca_item",
|
||
|
metadata,
|
||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||
|
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||
|
Column("item_id", Integer, nullable=False),
|
||
|
Column("type", Integer, nullable=False),
|
||
|
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
|
||
|
Column("use_count", Integer, server_default="0"),
|
||
|
UniqueConstraint("user", "item_id", "type", name="wacca_item_uk"),
|
||
|
mysql_charset='utf8mb4'
|
||
|
)
|
||
|
|
||
|
ticket = Table(
|
||
|
"wacca_ticket",
|
||
|
metadata,
|
||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||
|
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||
|
Column("ticket_id", Integer, nullable=False),
|
||
|
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
|
||
|
Column("expire_date", TIMESTAMP),
|
||
|
mysql_charset='utf8mb4'
|
||
|
)
|
||
|
|
||
|
song_unlock = Table(
|
||
|
"wacca_song_unlock",
|
||
|
metadata,
|
||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||
|
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||
|
Column("song_id", Integer, nullable=False),
|
||
|
Column("highest_difficulty", Integer, nullable=False),
|
||
|
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
|
||
|
UniqueConstraint("user", "song_id", name="wacca_song_unlock_uk"),
|
||
|
mysql_charset='utf8mb4'
|
||
|
)
|
||
|
|
||
|
trophy = Table(
|
||
|
"wacca_trophy",
|
||
|
metadata,
|
||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||
|
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||
|
Column("trophy_id", Integer, nullable=False),
|
||
|
Column("season", Integer, nullable=False),
|
||
|
Column("progress", Integer, nullable=False, server_default="0"),
|
||
|
Column("badge_type", Integer, nullable=False, server_default="0"),
|
||
|
UniqueConstraint("user", "trophy_id", "season", name="wacca_trophy_uk"),
|
||
|
mysql_charset='utf8mb4'
|
||
|
)
|
||
|
|
||
|
class WaccaItemData(BaseData):
|
||
|
def get_song_unlocks(self, user_id: int) -> Optional[List[Row]]:
|
||
|
sql = song_unlock.select(song_unlock.c.user == user_id)
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None: return None
|
||
|
|
||
|
return result.fetchall()
|
||
|
|
||
|
def unlock_song(self, user_id: int, song_id: int, difficulty: int) -> Optional[int]:
|
||
|
sql = insert(song_unlock).values(
|
||
|
user=user_id,
|
||
|
song_id=song_id,
|
||
|
highest_difficulty=difficulty
|
||
|
)
|
||
|
|
||
|
conflict = sql.on_duplicate_key_update(
|
||
|
highest_difficulty=case(
|
||
|
(song_unlock.c.highest_difficulty >= difficulty, song_unlock.c.highest_difficulty),
|
||
|
(song_unlock.c.highest_difficulty < difficulty, difficulty),
|
||
|
)
|
||
|
)
|
||
|
|
||
|
result = self.execute(conflict)
|
||
|
if result is None:
|
||
|
self.logger.error(f"{__name__} failed to unlock song! user: {user_id}, song_id: {song_id}, difficulty: {difficulty}")
|
||
|
return None
|
||
|
|
||
|
return result.lastrowid
|
||
|
|
||
|
def put_item(self, user_id: int, item_type: int, item_id: int) -> Optional[int]:
|
||
|
sql = insert(item).values(
|
||
|
user = user_id,
|
||
|
item_id = item_id,
|
||
|
type = item_type,
|
||
|
)
|
||
|
|
||
|
conflict = sql.on_duplicate_key_update(
|
||
|
use_count = item.c.use_count + 1
|
||
|
)
|
||
|
|
||
|
result = self.execute(conflict)
|
||
|
if result is None:
|
||
|
self.logger.error(f"{__name__} failed to insert item! user: {user_id}, item_id: {item_id}, item_type: {item_type}")
|
||
|
return None
|
||
|
|
||
|
return result.lastrowid
|
||
|
|
||
|
def get_items(self, user_id: int, item_type: int = None, item_id: int = None) -> Optional[List[Row]]:
|
||
|
"""
|
||
|
A catch-all item lookup given a profile and option item type and ID specifiers
|
||
|
"""
|
||
|
sql = item.select(
|
||
|
and_(item.c.user == user_id,
|
||
|
item.c.type == item_type if item_type is not None else True,
|
||
|
item.c.item_id == item_id if item_id is not None else True)
|
||
|
)
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None: return None
|
||
|
return result.fetchall()
|
||
|
|
||
|
def get_tickets(self, user_id: int) -> Optional[List[Row]]:
|
||
|
sql = select(ticket).where(ticket.c.user == user_id)
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None: return None
|
||
|
return result.fetchall()
|
||
|
|
||
|
def add_ticket(self, user_id: int, ticket_id: int) -> None:
|
||
|
sql = insert(ticket).values(
|
||
|
user = user_id,
|
||
|
ticket_id = ticket_id
|
||
|
)
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None:
|
||
|
self.logger.error(f"add_ticket: Failed to insert wacca ticket! user_id: {user_id} ticket_id {ticket_id}")
|
||
|
return None
|
||
|
return result.lastrowid
|
||
|
|
||
|
def spend_ticket(self, id: int) -> None:
|
||
|
sql = delete(ticket).where(ticket.c.id == id)
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None:
|
||
|
self.logger.warn(f"Failed to delete ticket id {id}")
|
||
|
return None
|
||
|
|
||
|
def get_trophies(self, user_id: int, season: int = None) -> Optional[List[Row]]:
|
||
|
if season is None:
|
||
|
sql = select(trophy).where(trophy.c.user == user_id)
|
||
|
else:
|
||
|
sql = select(trophy).where(and_(trophy.c.user == user_id, trophy.c.season == season))
|
||
|
|
||
|
result = self.execute(sql)
|
||
|
if result is None: return None
|
||
|
return result.fetchall()
|
||
|
|
||
|
def update_trophy(self, user_id: int, trophy_id: int, season: int, progress: int, badge_type: int) -> Optional[int]:
|
||
|
sql = insert(trophy).values(
|
||
|
user = user_id,
|
||
|
trophy_id = trophy_id,
|
||
|
season = season,
|
||
|
progress = progress,
|
||
|
badge_type = badge_type
|
||
|
)
|
||
|
|
||
|
conflict = sql.on_duplicate_key_update(
|
||
|
progress = progress
|
||
|
)
|
||
|
|
||
|
result = self.execute(conflict)
|
||
|
if result is None:
|
||
|
self.logger.error(f"update_trophy: Failed to insert wacca trophy! user_id: {user_id} trophy_id: {trophy_id} progress {progress}")
|
||
|
return None
|
||
|
return result.lastrowid
|
||
|
|