Adding SAO item table and adding party saving

This commit is contained in:
Midorica 2023-05-29 16:51:41 -04:00
parent 84cb786bde
commit d8af7be4a4
4 changed files with 299 additions and 70 deletions

View File

@ -73,7 +73,12 @@ class SaoBase:
user_id = -1 user_id = -1
self.logger.error("Failed to register card!") self.logger.error("Failed to register card!")
# Create profile with 3 basic heroes
profile_id = self.game_data.profile.create_profile(user_id) profile_id = self.game_data.profile.create_profile(user_id)
self.game_data.item.put_hero_log(user_id, 101000010, 1, 0, 101000016, 0, 30086, 1001, 1002, 1003, 1005)
self.game_data.item.put_hero_log(user_id, 102000010, 1, 0, 103000006, 0, 30086, 1001, 1002, 1003, 1005)
self.game_data.item.put_hero_log(user_id, 103000010, 1, 0, 112000009, 0, 30086, 1001, 1002, 1003, 1005)
self.game_data.item.put_hero_party(user_id, 0, 101000010, 102000010, 103000010)
self.logger.info(f"User Authenticated: { access_code } | { user_id }") self.logger.info(f"User Authenticated: { access_code } | { user_id }")
@ -121,9 +126,19 @@ class SaoBase:
def handle_c600(self, request: Any) -> bytes: def handle_c600(self, request: Any) -> bytes:
#have_object/get_hero_log_user_data_list #have_object/get_hero_log_user_data_list
heroIdsData = self.game_data.static.get_hero_ids(0, True) req = bytes.fromhex(request)[24:]
req_struct = Struct(
Padding(16),
"user_id_size" / Rebuild(Int32ub, len_(this.user_id) * 2), # calculates the length of the user_id
"user_id" / PaddedString(this.user_id_size, "utf_16_le"), # user_id is a (zero) padded string
resp = SaoGetHeroLogUserDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, heroIdsData) )
req_data = req_struct.parse(req)
user_id = req_data.user_id
hero_data = self.game_data.item.get_hero_logs(user_id)
resp = SaoGetHeroLogUserDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, hero_data)
return resp.make() return resp.make()
def handle_c602(self, request: Any) -> bytes: def handle_c602(self, request: Any) -> bytes:
@ -164,7 +179,23 @@ class SaoBase:
def handle_c804(self, request: Any) -> bytes: def handle_c804(self, request: Any) -> bytes:
#custom/get_party_data_list #custom/get_party_data_list
resp = SaoGetPartyDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
req = bytes.fromhex(request)[24:]
req_struct = Struct(
Padding(16),
"user_id_size" / Rebuild(Int32ub, len_(this.user_id) * 2), # calculates the length of the user_id
"user_id" / PaddedString(this.user_id_size, "utf_16_le"), # user_id is a (zero) padded string
)
req_data = req_struct.parse(req)
user_id = req_data.user_id
hero_party = self.game_data.item.get_hero_party(user_id, 0)
hero1_data = self.game_data.item.get_hero_log(user_id, hero_party[3])
hero2_data = self.game_data.item.get_hero_log(user_id, hero_party[4])
hero3_data = self.game_data.item.get_hero_log(user_id, hero_party[5])
resp = SaoGetPartyDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, hero1_data, hero2_data, hero3_data)
return resp.make() return resp.make()
def handle_c902(self, request: Any) -> bytes: # for whatever reason, having all entries empty or filled changes nothing def handle_c902(self, request: Any) -> bytes: # for whatever reason, having all entries empty or filled changes nothing
@ -228,18 +259,40 @@ class SaoBase:
"sub_equipment_user_equipment_id_size" / Rebuild(Int32ub, len_(this.sub_equipment_user_equipment_id) * 2), # calculates the length of the sub_equipment_user_equipment_id "sub_equipment_user_equipment_id_size" / Rebuild(Int32ub, len_(this.sub_equipment_user_equipment_id) * 2), # calculates the length of the sub_equipment_user_equipment_id
"sub_equipment_user_equipment_id" / PaddedString(this.sub_equipment_user_equipment_id_size, "utf_16_le"), # sub_equipment_user_equipment_id is a (zero) padded string "sub_equipment_user_equipment_id" / PaddedString(this.sub_equipment_user_equipment_id_size, "utf_16_le"), # sub_equipment_user_equipment_id is a (zero) padded string
"skill_slot1_skill_id" / Int32ub, # skill_slot1_skill_id is a int, "skill_slot1_skill_id" / Int32ub, # skill_slot1_skill_id is a int,
"skill_slot2_skill_id" / Int32ub, # skill_slot2_skill_id is a int, "skill_slot2_skill_id" / Int32ub, # skill_slot1_skill_id is a int,
"skill_slot3_skill_id" / Int32ub, # skill_slot3_skill_id is a int, "skill_slot3_skill_id" / Int32ub, # skill_slot1_skill_id is a int,
"skill_slot4_skill_id" / Int32ub, # skill_slot4_skill_id is a int, "skill_slot4_skill_id" / Int32ub, # skill_slot1_skill_id is a int,
"skill_slot5_skill_id" / Int32ub, # skill_slot5_skill_id is a int, "skill_slot5_skill_id" / Int32ub, # skill_slot1_skill_id is a int,
)), )),
)), )),
) )
req_data = req_struct.parse(req) req_data = req_struct.parse(req)
user_id = req_data.user_id
#self.logger.info(f"User Team Data: { req_data }") for party_team in req_data.party_data_list[0].party_team_data_list:
hero_data = self.game_data.item.get_hero_log(user_id, party_team["user_hero_log_id"])
hero_level = 1
hero_exp = 0
if hero_data:
hero_level = hero_data["log_level"]
hero_exp = hero_data["log_exp"]
self.game_data.item.put_hero_log(
user_id,
party_team["user_hero_log_id"],
hero_level,
hero_exp,
party_team["main_weapon_user_equipment_id"],
party_team["sub_equipment_user_equipment_id"],
party_team["skill_slot1_skill_id"],
party_team["skill_slot2_skill_id"],
party_team["skill_slot3_skill_id"],
party_team["skill_slot4_skill_id"],
party_team["skill_slot5_skill_id"]
)
resp = SaoNoopResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1) resp = SaoNoopResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
return resp.make() return resp.make()
@ -371,12 +424,6 @@ class SaoBase:
req_data = req_struct.parse(req) req_data = req_struct.parse(req)
#self.logger.info(f"User Get Col Data: { req_data.get_col }")
#self.logger.info(f"User Hero Log Exp Data: { req_data.get_hero_log_exp }")
#self.logger.info(f"User Score Data: { req_data.score_data[0] }")
#self.logger.info(f"User Discovery Enemy Data: { req_data.discovery_enemy_data_list }")
#self.logger.info(f"User Mission Data: { req_data.mission_data_list }")
resp = SaoEpisodePlayEndResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1) resp = SaoEpisodePlayEndResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
return resp.make() return resp.make()

View File

@ -478,28 +478,49 @@ class SaoGetHeroLogUserDataListRequest(SaoBaseRequest):
super().__init__(data) super().__init__(data)
class SaoGetHeroLogUserDataListResponse(SaoBaseResponse): class SaoGetHeroLogUserDataListResponse(SaoBaseResponse):
def __init__(self, cmd, heroIdsData) -> None: def __init__(self, cmd, hero_data) -> None:
super().__init__(cmd) super().__init__(cmd)
self.result = 1 self.result = 1
#print(heroIdsData) self.user_hero_log_id = []
#print(list(map(str,heroIdsData))) self.log_level = []
self.max_log_level_extended_num = []
self.log_exp = []
self.last_set_skill_slot1_skill_id = []
self.last_set_skill_slot2_skill_id = []
self.last_set_skill_slot3_skill_id = []
self.last_set_skill_slot4_skill_id = []
self.last_set_skill_slot5_skill_id = []
for i in range(len(hero_data)):
self.user_hero_log_id.append(hero_data[i][2])
self.log_level.append(hero_data[i][3])
self.max_log_level_extended_num.append(hero_data[i][3])
self.log_exp.append(hero_data[i][4])
self.last_set_skill_slot1_skill_id.append(hero_data[i][7])
self.last_set_skill_slot2_skill_id.append(hero_data[i][8])
self.last_set_skill_slot3_skill_id.append(hero_data[i][9])
self.last_set_skill_slot4_skill_id.append(hero_data[i][10])
self.last_set_skill_slot5_skill_id.append(hero_data[i][11])
#print(self.user_hero_log_id)
#print(list(map(str,self.user_hero_log_id)))
# hero_log_user_data_list # hero_log_user_data_list
self.user_hero_log_id = list(map(str,heroIdsData)) #str self.user_hero_log_id = list(map(str,self.user_hero_log_id)) #str
self.hero_log_id = heroIdsData #int self.hero_log_id = list(map(int,self.user_hero_log_id)) #int
self.log_level = 10 #short self.log_level = list(map(int,self.log_level)) #short
self.max_log_level_extended_num = 10 #short self.max_log_level_extended_num = list(map(int,self.log_level)) #short
self.log_exp = 1000 #int self.log_exp = list(map(int,self.log_level)) #int
self.possible_awakening_flag = 0 #byte self.possible_awakening_flag = 0 #byte
self.awakening_stage = 0 #short self.awakening_stage = 0 #short
self.awakening_exp = 0 #int self.awakening_exp = 0 #int
self.skill_slot_correction_value = 0 #byte self.skill_slot_correction_value = 0 #byte
self.last_set_skill_slot1_skill_id = 0 #short self.last_set_skill_slot1_skill_id = list(map(int,self.last_set_skill_slot1_skill_id)) #short
self.last_set_skill_slot2_skill_id = 0 #short self.last_set_skill_slot2_skill_id = list(map(int,self.last_set_skill_slot2_skill_id)) #short
self.last_set_skill_slot3_skill_id = 0 #short self.last_set_skill_slot3_skill_id = list(map(int,self.last_set_skill_slot3_skill_id)) #short
self.last_set_skill_slot4_skill_id = 0 #short self.last_set_skill_slot4_skill_id = list(map(int,self.last_set_skill_slot4_skill_id)) #short
self.last_set_skill_slot5_skill_id = 0 #short self.last_set_skill_slot5_skill_id = list(map(int,self.last_set_skill_slot5_skill_id)) #short
self.property1_property_id = 0 #int self.property1_property_id = 0 #int
self.property1_value1 = 0 #int self.property1_value1 = 0 #int
self.property1_value2 = 0 #int self.property1_value2 = 0 #int
@ -573,18 +594,18 @@ class SaoGetHeroLogUserDataListResponse(SaoBaseResponse):
user_hero_log_id_size=len(self.user_hero_log_id[i]) * 2, user_hero_log_id_size=len(self.user_hero_log_id[i]) * 2,
user_hero_log_id=[ord(x) for x in self.user_hero_log_id[i]], user_hero_log_id=[ord(x) for x in self.user_hero_log_id[i]],
hero_log_id=self.hero_log_id[i], hero_log_id=self.hero_log_id[i],
log_level=self.log_level, log_level=self.log_level[i],
max_log_level_extended_num=self.max_log_level_extended_num, max_log_level_extended_num=self.max_log_level_extended_num[i],
log_exp=self.log_exp, log_exp=self.log_exp[i],
possible_awakening_flag=self.possible_awakening_flag, possible_awakening_flag=self.possible_awakening_flag,
awakening_stage=self.awakening_stage, awakening_stage=self.awakening_stage,
awakening_exp=self.awakening_exp, awakening_exp=self.awakening_exp,
skill_slot_correction_value=self.skill_slot_correction_value, skill_slot_correction_value=self.skill_slot_correction_value,
last_set_skill_slot1_skill_id=self.last_set_skill_slot1_skill_id, last_set_skill_slot1_skill_id=self.last_set_skill_slot1_skill_id[i],
last_set_skill_slot2_skill_id=self.last_set_skill_slot2_skill_id, last_set_skill_slot2_skill_id=self.last_set_skill_slot2_skill_id[i],
last_set_skill_slot3_skill_id=self.last_set_skill_slot3_skill_id, last_set_skill_slot3_skill_id=self.last_set_skill_slot3_skill_id[i],
last_set_skill_slot4_skill_id=self.last_set_skill_slot4_skill_id, last_set_skill_slot4_skill_id=self.last_set_skill_slot4_skill_id[i],
last_set_skill_slot5_skill_id=self.last_set_skill_slot5_skill_id, last_set_skill_slot5_skill_id=self.last_set_skill_slot5_skill_id[i],
property1_property_id=self.property1_property_id, property1_property_id=self.property1_property_id,
property1_value1=self.property1_value1, property1_value1=self.property1_value1,
property1_value2=self.property1_value2, property1_value2=self.property1_value2,
@ -926,10 +947,10 @@ class SaoGetEpisodeAppendDataListResponse(SaoBaseResponse):
def make(self) -> bytes: def make(self) -> bytes:
episode_data_struct = Struct( episode_data_struct = Struct(
"user_episode_append_id_size" / Int32ub, # big endian "user_episode_append_id_size" / Rebuild(Int32ub, len_(this.user_episode_append_id) * 2), # calculates the length of the user_episode_append_id
"user_episode_append_id" / Int16ul[5], #forced to match the user_episode_append_id_list index which is always 5 chars for the episode ids "user_episode_append_id" / PaddedString(this.user_episode_append_id_size, "utf_16_le"), # user_episode_append_id is a (zero) padded string
"user_id_size" / Int32ub, # big endian "user_id_size" / Rebuild(Int32ub, len_(this.user_id) * 2), # calculates the length of the user_id
"user_id" / Int16ul[6], # has to be exactly 6 chars in the user field... MANDATORY "user_id" / PaddedString(this.user_id_size, "utf_16_le"), # user_id is a (zero) padded string
"episode_append_id" / Int32ub, "episode_append_id" / Int32ub,
"own_num" / Int32ub, "own_num" / Int32ub,
) )
@ -955,10 +976,8 @@ class SaoGetEpisodeAppendDataListResponse(SaoBaseResponse):
for i in range(len(self.user_id_list)): for i in range(len(self.user_id_list)):
# add the episode_data_struct to the resp_struct.episode_append_data_list # add the episode_data_struct to the resp_struct.episode_append_data_list
resp_data.episode_append_data_list.append(dict( resp_data.episode_append_data_list.append(dict(
user_episode_append_id_size=len(self.user_episode_append_id_list[i]) * 2, user_episode_append_id=self.user_episode_append_id_list[i],
user_episode_append_id=[ord(x) for x in self.user_episode_append_id_list[i]], user_id=self.user_id_list[i],
user_id_size=len(self.user_id_list[i]) * 2,
user_id=[ord(x) for x in self.user_id_list[i]],
episode_append_id=self.episode_append_id_list[i], episode_append_id=self.episode_append_id_list[i],
own_num=self.own_num_list[i], own_num=self.own_num_list[i],
)) ))
@ -974,8 +993,9 @@ class SaoGetPartyDataListRequest(SaoBaseRequest):
super().__init__(data) super().__init__(data)
class SaoGetPartyDataListResponse(SaoBaseResponse): # Default party class SaoGetPartyDataListResponse(SaoBaseResponse): # Default party
def __init__(self, cmd) -> None: def __init__(self, cmd, hero1_data, hero2_data, hero3_data) -> None:
super().__init__(cmd) super().__init__(cmd)
self.result = 1 self.result = 1
self.party_data_list_size = 1 # Number of arrays self.party_data_list_size = 1 # Number of arrays
@ -985,36 +1005,36 @@ class SaoGetPartyDataListResponse(SaoBaseResponse): # Default party
self.user_party_team_id_1 = "0" self.user_party_team_id_1 = "0"
self.arrangement_num_1 = 0 self.arrangement_num_1 = 0
self.user_hero_log_id_1 = "101000010" self.user_hero_log_id_1 = str(hero1_data[2])
self.main_weapon_user_equipment_id_1 = "101000016" self.main_weapon_user_equipment_id_1 = str(hero1_data[5])
self.sub_equipment_user_equipment_id_1 = "0" self.sub_equipment_user_equipment_id_1 = str(hero1_data[6])
self.skill_slot1_skill_id_1 = 30086 self.skill_slot1_skill_id_1 = hero1_data[7]
self.skill_slot2_skill_id_1 = 1001 self.skill_slot2_skill_id_1 = hero1_data[8]
self.skill_slot3_skill_id_1 = 1002 self.skill_slot3_skill_id_1 = hero1_data[9]
self.skill_slot4_skill_id_1 = 1003 self.skill_slot4_skill_id_1 = hero1_data[10]
self.skill_slot5_skill_id_1 = 1005 self.skill_slot5_skill_id_1 = hero1_data[11]
self.user_party_team_id_2 = "0" self.user_party_team_id_2 = "0"
self.arrangement_num_2 = 0 self.arrangement_num_2 = 0
self.user_hero_log_id_2 = "102000010" self.user_hero_log_id_2 = str(hero2_data[2])
self.main_weapon_user_equipment_id_2 = "103000006" self.main_weapon_user_equipment_id_2 = str(hero2_data[5])
self.sub_equipment_user_equipment_id_2 = "0" self.sub_equipment_user_equipment_id_2 = str(hero2_data[6])
self.skill_slot1_skill_id_2 = 30086 self.skill_slot1_skill_id_2 = hero2_data[7]
self.skill_slot2_skill_id_2 = 1001 self.skill_slot2_skill_id_2 = hero2_data[8]
self.skill_slot3_skill_id_2 = 1002 self.skill_slot3_skill_id_2 = hero2_data[9]
self.skill_slot4_skill_id_2 = 1003 self.skill_slot4_skill_id_2 = hero2_data[10]
self.skill_slot5_skill_id_2 = 1005 self.skill_slot5_skill_id_2 = hero2_data[11]
self.user_party_team_id_3 = "0" self.user_party_team_id_3 = "0"
self.arrangement_num_3 = 0 self.arrangement_num_3 = 0
self.user_hero_log_id_3 = "103000010" self.user_hero_log_id_3 = str(hero3_data[2])
self.main_weapon_user_equipment_id_3 = "112000009" self.main_weapon_user_equipment_id_3 = str(hero3_data[5])
self.sub_equipment_user_equipment_id_3 = "0" self.sub_equipment_user_equipment_id_3 = str(hero3_data[6])
self.skill_slot1_skill_id_3 = 30086 self.skill_slot1_skill_id_3 = hero3_data[7]
self.skill_slot2_skill_id_3 = 1001 self.skill_slot2_skill_id_3 = hero3_data[8]
self.skill_slot3_skill_id_3 = 1002 self.skill_slot3_skill_id_3 = hero3_data[9]
self.skill_slot4_skill_id_3 = 1003 self.skill_slot4_skill_id_3 = hero3_data[10]
self.skill_slot5_skill_id_3 = 1005 self.skill_slot5_skill_id_3 = hero3_data[11]
def make(self) -> bytes: def make(self) -> bytes:
# create a resp struct # create a resp struct

View File

@ -1,2 +1,3 @@
from .profile import SaoProfileData from .profile import SaoProfileData
from .static import SaoStaticData from .static import SaoStaticData
from .item import SaoItemData

161
titles/sao/schema/item.py Normal file
View File

@ -0,0 +1,161 @@
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
hero_log_data = Table(
"sao_hero_log_data",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("user_hero_log_id", Integer, nullable=False),
Column("log_level", Integer, nullable=False),
Column("log_exp", Integer, nullable=False),
Column("main_weapon", Integer, nullable=False),
Column("sub_equipment", Integer, nullable=False),
Column("skill_slot1_skill_id", Integer, nullable=False),
Column("skill_slot2_skill_id", Integer, nullable=False),
Column("skill_slot3_skill_id", Integer, nullable=False),
Column("skill_slot4_skill_id", Integer, nullable=False),
Column("skill_slot5_skill_id", Integer, nullable=False),
Column("get_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "user_hero_log_id", name="sao_hero_log_data_uk"),
mysql_charset="utf8mb4",
)
hero_party = Table(
"sao_hero_party",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("user_party_team_id", Integer, nullable=False),
Column("user_hero_log_id_1", Integer, nullable=False),
Column("user_hero_log_id_2", Integer, nullable=False),
Column("user_hero_log_id_3", Integer, nullable=False),
UniqueConstraint("user", "user_party_team_id", name="sao_hero_party_uk"),
mysql_charset="utf8mb4",
)
class SaoItemData(BaseData):
def put_hero_log(self, user_id: int, user_hero_log_id: int, log_level: int, log_exp: int, main_weapon: int, sub_equipment: int, skill_slot1_skill_id: int, skill_slot2_skill_id: int, skill_slot3_skill_id: int, skill_slot4_skill_id: int, skill_slot5_skill_id: int) -> Optional[int]:
sql = insert(hero_log_data).values(
user=user_id,
user_hero_log_id=user_hero_log_id,
log_level=log_level,
log_exp=log_exp,
main_weapon=main_weapon,
sub_equipment=sub_equipment,
skill_slot1_skill_id=skill_slot1_skill_id,
skill_slot2_skill_id=skill_slot2_skill_id,
skill_slot3_skill_id=skill_slot3_skill_id,
skill_slot4_skill_id=skill_slot4_skill_id,
skill_slot5_skill_id=skill_slot5_skill_id,
)
conflict = sql.on_duplicate_key_update(
log_level=hero_log_data.c.log_level,
log_exp=hero_log_data.c.log_exp,
main_weapon=hero_log_data.c.main_weapon,
sub_equipment=hero_log_data.c.sub_equipment,
skill_slot1_skill_id=hero_log_data.c.skill_slot1_skill_id,
skill_slot2_skill_id=hero_log_data.c.skill_slot2_skill_id,
skill_slot3_skill_id=hero_log_data.c.skill_slot3_skill_id,
skill_slot4_skill_id=hero_log_data.c.skill_slot4_skill_id,
skill_slot5_skill_id=hero_log_data.c.skill_slot5_skill_id,
)
result = self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert hero! user: {user_id}, user_hero_log_id: {user_hero_log_id}"
)
return None
return result.lastrowid
def put_hero_party(self, user_id: int, user_party_team_id: int, user_hero_log_id_1: int, user_hero_log_id_2: int, user_hero_log_id_3: int) -> Optional[int]:
sql = insert(hero_party).values(
user=user_id,
user_party_team_id=user_party_team_id,
user_hero_log_id_1=user_hero_log_id_1,
user_hero_log_id_2=user_hero_log_id_2,
user_hero_log_id_3=user_hero_log_id_3,
)
conflict = sql.on_duplicate_key_update(
user_hero_log_id_1=hero_party.c.user_hero_log_id_1,
user_hero_log_id_2=hero_party.c.user_hero_log_id_2,
user_hero_log_id_3=hero_party.c.user_hero_log_id_3,
)
result = self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert hero party! user: {user_id}, user_party_team_id: {user_party_team_id}"
)
return None
return result.lastrowid
def get_hero_log(
self, user_id: int, user_hero_log_id: int = None
) -> Optional[List[Row]]:
"""
A catch-all hero lookup given a profile and user_party_team_id and ID specifiers
"""
sql = hero_log_data.select(
and_(
hero_log_data.c.user == user_id,
hero_log_data.c.user_hero_log_id == user_hero_log_id if user_hero_log_id is not None else True,
)
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_hero_logs(
self, user_id: int
) -> Optional[List[Row]]:
"""
A catch-all hero lookup given a profile and user_party_team_id and ID specifiers
"""
sql = hero_log_data.select(
and_(
hero_log_data.c.user == user_id,
)
)
result = self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_hero_party(
self, user_id: int, user_party_team_id: int = None
) -> Optional[List[Row]]:
sql = hero_party.select(
and_(
hero_party.c.user == user_id,
hero_party.c.user_party_team_id == user_party_team_id if user_party_team_id is not None else True,
)
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()