forked from Hay1tsme/artemis
Begin the process of transitioning from megaime
This commit is contained in:
2
core/data/__init__.py
Normal file
2
core/data/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from core.data.database import Data
|
||||
from core.data.cache import cached
|
65
core/data/cache.py
Normal file
65
core/data/cache.py
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
from typing import Any, Callable
|
||||
from functools import wraps
|
||||
import hashlib
|
||||
import pickle
|
||||
import logging
|
||||
from core.config import CoreConfig
|
||||
|
||||
cfg:CoreConfig = None # type: ignore
|
||||
# Make memcache optional
|
||||
try:
|
||||
import pylibmc # type: ignore
|
||||
has_mc = True
|
||||
except ModuleNotFoundError:
|
||||
has_mc = False
|
||||
|
||||
def cached(lifetime: int=10, extra_key: Any=None) -> Callable:
|
||||
def _cached(func: Callable) -> Callable:
|
||||
if has_mc:
|
||||
hostname = "127.0.0.1"
|
||||
if cfg:
|
||||
hostname = cfg.database.memcached_host
|
||||
memcache = pylibmc.Client([hostname], binary=True)
|
||||
memcache.behaviors = {"tcp_nodelay": True, "ketama": True}
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
if lifetime is not None:
|
||||
|
||||
# Hash function args
|
||||
items = kwargs.items()
|
||||
hashable_args = (args[1:], sorted(list(items)))
|
||||
args_key = hashlib.md5(pickle.dumps(hashable_args)).hexdigest()
|
||||
|
||||
# Generate unique cache key
|
||||
cache_key = f'{func.__module__}-{func.__name__}-{args_key}-{extra_key() if hasattr(extra_key, "__call__") else extra_key}'
|
||||
|
||||
# Return cached version if allowed and available
|
||||
try:
|
||||
result = memcache.get(cache_key)
|
||||
except pylibmc.Error as e:
|
||||
logging.getLogger("database").error(f"Memcache failed: {e}")
|
||||
result = None
|
||||
|
||||
if result is not None:
|
||||
logging.getLogger("database").debug(f"Cache hit: {result}")
|
||||
return result
|
||||
|
||||
# Generate output
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
# Cache output if allowed
|
||||
if lifetime is not None and result is not None:
|
||||
logging.getLogger("database").debug(f"Setting cache: {result}")
|
||||
memcache.set(cache_key, result, lifetime)
|
||||
|
||||
return result
|
||||
else:
|
||||
@wraps(func)
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return _cached
|
53
core/data/database.py
Normal file
53
core/data/database.py
Normal file
@ -0,0 +1,53 @@
|
||||
import logging, coloredlogs
|
||||
from typing import Any, Dict, List
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import create_engine
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
from hashlib import sha256
|
||||
|
||||
from core.config import CoreConfig
|
||||
from core.data.schema import *
|
||||
|
||||
class Data:
|
||||
def __init__(self, cfg: CoreConfig) -> None:
|
||||
self.config = cfg
|
||||
|
||||
if self.config.database.sha2_password:
|
||||
passwd = sha256(self.config.database.password.encode()).digest()
|
||||
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{passwd.hex()}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4"
|
||||
else:
|
||||
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{self.config.database.password}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4"
|
||||
|
||||
self.__engine = create_engine(self.__url, pool_recycle=3600)
|
||||
session = sessionmaker(bind=self.__engine, autoflush=True, autocommit=True)
|
||||
self.session = scoped_session(session)
|
||||
|
||||
self.user = UserData(self.config, self.session)
|
||||
self.arcade = ArcadeData(self.config, self.session)
|
||||
self.card = CardData(self.config, self.session)
|
||||
self.base = BaseData(self.config, self.session)
|
||||
self.schema_ver_latest = 1
|
||||
|
||||
log_fmt_str = "[%(asctime)s] %(levelname)s | Database | %(message)s"
|
||||
log_fmt = logging.Formatter(log_fmt_str)
|
||||
self.logger = logging.getLogger("database")
|
||||
|
||||
# Prevent the logger from adding handlers multiple times
|
||||
if not getattr(self.logger, 'handler_set', None):
|
||||
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.config.server.logs, "db"), encoding="utf-8",
|
||||
when="d", backupCount=10)
|
||||
fileHandler.setFormatter(log_fmt)
|
||||
|
||||
consoleHandler = logging.StreamHandler()
|
||||
consoleHandler.setFormatter(log_fmt)
|
||||
|
||||
self.logger.addHandler(fileHandler)
|
||||
self.logger.addHandler(consoleHandler)
|
||||
|
||||
self.logger.setLevel(self.config.database.loglevel)
|
||||
coloredlogs.install(cfg.database.loglevel, logger=self.logger, fmt=log_fmt_str)
|
||||
self.logger.handler_set = True # type: ignore
|
||||
|
||||
|
6
core/data/schema/__init__.py
Normal file
6
core/data/schema/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from core.data.schema.user import UserData
|
||||
from core.data.schema.card import CardData
|
||||
from core.data.schema.base import BaseData, metadata
|
||||
from core.data.schema.arcade import ArcadeData
|
||||
|
||||
__all__ = ["UserData", "CardData", "BaseData", "metadata", "ArcadeData"]
|
113
core/data/schema/arcade.py
Normal file
113
core/data/schema/arcade.py
Normal file
@ -0,0 +1,113 @@
|
||||
from typing import Optional, Dict
|
||||
from sqlalchemy import Table, Column
|
||||
from sqlalchemy.sql.schema import ForeignKey, PrimaryKeyConstraint
|
||||
from sqlalchemy.types import Integer, String, Boolean
|
||||
from sqlalchemy.sql import func, select
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.data.schema.base import BaseData, metadata
|
||||
|
||||
arcade = Table(
|
||||
"arcade",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("name", String(255)),
|
||||
Column("nickname", String(255)),
|
||||
Column("country", String(3)),
|
||||
Column("country_id", Integer),
|
||||
Column("state", String(255)),
|
||||
Column("city", String(255)),
|
||||
Column("region_id", Integer),
|
||||
Column("timezone", String(255)),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
machine = Table(
|
||||
"machine",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("arcade", ForeignKey("arcade.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column("serial", String(15), nullable=False),
|
||||
Column("board", String(15)),
|
||||
Column("game", String(4)),
|
||||
Column("country", String(3)), # overwrites if not null
|
||||
Column("timezone", String(255)),
|
||||
Column("ota_enable", Boolean),
|
||||
Column("is_cab", Boolean),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
arcade_owner = Table(
|
||||
'arcade_owner',
|
||||
metadata,
|
||||
Column('user', Integer, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column('arcade', Integer, ForeignKey("arcade.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column('permissions', Integer, nullable=False),
|
||||
PrimaryKeyConstraint('user', 'arcade', name='arcade_owner_pk'),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class ArcadeData(BaseData):
|
||||
def get_machine(self, serial: str = None, id: int = None) -> Optional[Dict]:
|
||||
if serial is not None:
|
||||
sql = machine.select(machine.c.serial == serial)
|
||||
elif id is not None:
|
||||
sql = machine.select(machine.c.id == id)
|
||||
else:
|
||||
self.logger.error(f"{__name__ }: Need either serial or ID to look up!")
|
||||
return None
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
|
||||
def put_machine(self, arcade_id: int, serial: str = None, board: str = None, game: str = None, is_cab: bool = False) -> Optional[int]:
|
||||
if arcade_id:
|
||||
self.logger.error(f"{__name__ }: Need arcade id!")
|
||||
return None
|
||||
|
||||
if serial is None:
|
||||
pass
|
||||
|
||||
sql = machine.insert().values(arcade = arcade_id, keychip = serial, board = board, game = game, is_cab = is_cab)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_arcade(self, id: int) -> Optional[Dict]:
|
||||
sql = arcade.select(arcade.c.id == id)
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
|
||||
def put_arcade(self, name: str, nickname: str = None, country: str = "JPN", country_id: int = 1,
|
||||
state: str = "", city: str = "", regional_id: int = 1) -> Optional[int]:
|
||||
if nickname is None: nickname = name
|
||||
|
||||
sql = arcade.insert().values(name = name, nickname = nickname, country = country, country_id = country_id,
|
||||
state = state, city = city, regional_id = regional_id)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_arcade_owners(self, arcade_id: int) -> Optional[Dict]:
|
||||
sql = select(arcade_owner).where(arcade_owner.c.arcade==arcade_id)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def add_arcade_owner(self, arcade_id: int, user_id: int) -> None:
|
||||
sql = insert(arcade_owner).values(
|
||||
arcade=arcade_id,
|
||||
user=user_id
|
||||
)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def generate_keychip_serial(self, platform_id: int) -> str:
|
||||
pass
|
124
core/data/schema/base.py
Normal file
124
core/data/schema/base.py
Normal file
@ -0,0 +1,124 @@
|
||||
import json
|
||||
import logging
|
||||
from random import randrange
|
||||
from typing import Any, Optional, Dict, List
|
||||
from sqlalchemy.engine.cursor import CursorResult
|
||||
from sqlalchemy.engine.base import Connection
|
||||
from sqlalchemy.sql import text, func, select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import MetaData, Table, Column
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, JSON
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.config import CoreConfig
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
schema_ver = Table(
|
||||
"schema_versions",
|
||||
metadata,
|
||||
Column("game", String(4), primary_key=True, nullable=False),
|
||||
Column("version", Integer, nullable=False, server_default="1"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
event_log = Table(
|
||||
"event_log",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("system", String(255), nullable=False),
|
||||
Column("type", String(255), nullable=False),
|
||||
Column("severity", Integer, nullable=False),
|
||||
Column("details", JSON, nullable=False),
|
||||
Column("when_logged", TIMESTAMP, nullable=False, server_default=func.now()),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class BaseData():
|
||||
def __init__(self, cfg: CoreConfig, conn: Connection) -> None:
|
||||
self.config = cfg
|
||||
self.conn = conn
|
||||
self.logger = logging.getLogger("database")
|
||||
|
||||
def execute(self, sql: str, opts: Dict[str, Any]={}) -> Optional[CursorResult]:
|
||||
res = None
|
||||
|
||||
try:
|
||||
self.logger.info(f"SQL Execute: {''.join(str(sql).splitlines())} || {opts}")
|
||||
res = self.conn.execute(text(sql), opts)
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"SQLAlchemy error {e}")
|
||||
return None
|
||||
|
||||
except UnicodeEncodeError as e:
|
||||
self.logger.error(f"UnicodeEncodeError error {e}")
|
||||
return None
|
||||
|
||||
except:
|
||||
try:
|
||||
res = self.conn.execute(sql, opts)
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
self.logger.error(f"SQLAlchemy error {e}")
|
||||
return None
|
||||
|
||||
except UnicodeEncodeError as e:
|
||||
self.logger.error(f"UnicodeEncodeError error {e}")
|
||||
return None
|
||||
|
||||
except:
|
||||
self.logger.error(f"Unknown error")
|
||||
raise
|
||||
|
||||
return res
|
||||
|
||||
def generate_id(self) -> int:
|
||||
"""
|
||||
Generate a random 5-7 digit id
|
||||
"""
|
||||
return randrange(10000, 9999999)
|
||||
|
||||
def get_schema_ver(self, game: str) -> Optional[int]:
|
||||
sql = select(schema_ver).where(schema_ver.c.game == game)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None:
|
||||
return None
|
||||
return result.fetchone()["version"]
|
||||
|
||||
def set_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]:
|
||||
sql = insert(schema_ver).values(game = game, version = ver)
|
||||
conflict = sql.on_duplicate_key_update(version = ver)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update schema version for game {game} (v{ver})")
|
||||
return None
|
||||
return result.lastrowid
|
||||
|
||||
def log_event(self, system: str, type: str, severity: int, details: Dict) -> Optional[int]:
|
||||
sql = event_log.insert().values(system = system, type = type, severity = severity, details = json.dumps(details))
|
||||
result = self.execute(sql)
|
||||
|
||||
if result is None:
|
||||
self.logger.error(f"{__name__}: Failed to insert event into event log! system = {system}, type = {type}, severity = {severity}, details = {details}")
|
||||
return None
|
||||
|
||||
return result.lastrowid
|
||||
|
||||
def get_event_log(self, entries: int = 100) -> Optional[List[Dict]]:
|
||||
sql = event_log.select().limit(entries).all()
|
||||
result = self.execute(sql)
|
||||
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def fix_bools(self, data: Dict) -> Dict:
|
||||
for k,v in data.items():
|
||||
if type(v) == str and v.lower() == "true":
|
||||
data[k] = True
|
||||
elif type(v) == str and v.lower() == "false":
|
||||
data[k] = False
|
||||
|
||||
return data
|
67
core/data/schema/card.py
Normal file
67
core/data/schema/card.py
Normal file
@ -0,0 +1,67 @@
|
||||
from typing import Dict, List, Optional
|
||||
from sqlalchemy import Table, Column, UniqueConstraint
|
||||
from sqlalchemy.types import Integer, String, Boolean, TIMESTAMP
|
||||
from sqlalchemy.sql.schema import ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from core.data.schema.base import BaseData, metadata
|
||||
|
||||
aime_card = Table(
|
||||
'aime_card',
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column("access_code", String(20)),
|
||||
Column("created_date", TIMESTAMP, server_default=func.now()),
|
||||
Column("last_login_date", TIMESTAMP, onupdate=func.now()),
|
||||
Column("is_locked", Boolean, server_default="0"),
|
||||
Column("is_banned", Boolean, server_default="0"),
|
||||
UniqueConstraint("user", "access_code", name="aime_card_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class CardData(BaseData):
|
||||
def get_user_id_from_card(self, access_code: str) -> Optional[int]:
|
||||
"""
|
||||
Given a 20 digit access code as a string, get the user id associated with that card
|
||||
"""
|
||||
sql = aime_card.select(aime_card.c.access_code == access_code)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
|
||||
card = result.fetchone()
|
||||
if card is None: return None
|
||||
|
||||
return int(card["user"])
|
||||
|
||||
def get_user_cards(self, aime_id: int) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Returns all cards owned by a user
|
||||
"""
|
||||
sql = aime_card.select(aime_card.c.user == aime_id)
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
|
||||
def create_card(self, user_id: int, access_code: str) -> Optional[int]:
|
||||
"""
|
||||
Given a aime_user id and a 20 digit access code as a string, create a card and return the ID if successful
|
||||
"""
|
||||
sql = aime_card.insert().values(user=user_id, access_code=access_code)
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def to_access_code(self, luid: str) -> str:
|
||||
"""
|
||||
Given a felica cards internal 16 hex character luid, convert it to a 0-padded 20 digit access code as a string
|
||||
"""
|
||||
return f"{int(luid, base=16):0{20}}"
|
||||
|
||||
def to_idm(self, access_code: str) -> str:
|
||||
"""
|
||||
Given a 20 digit access code as a string, return the 16 hex character luid
|
||||
"""
|
||||
return f'{int(access_code):0{16}x}'
|
57
core/data/schema/user.py
Normal file
57
core/data/schema/user.py
Normal file
@ -0,0 +1,57 @@
|
||||
from enum import Enum
|
||||
from typing import Dict, Optional
|
||||
from sqlalchemy import Table, Column
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP
|
||||
from sqlalchemy.sql.schema import ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from core.data.schema.base import BaseData, metadata
|
||||
|
||||
aime_user = Table(
|
||||
"aime_user",
|
||||
metadata,
|
||||
Column("id", Integer, nullable=False, primary_key=True, autoincrement=True),
|
||||
Column("username", String(25), unique=True),
|
||||
Column("email", String(255), unique=True),
|
||||
Column("password", String(255)),
|
||||
Column("permissions", Integer),
|
||||
Column("created_date", TIMESTAMP, server_default=func.now()),
|
||||
Column("last_login_date", TIMESTAMP, onupdate=func.now()),
|
||||
Column("suspend_expire_time", TIMESTAMP),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
frontend_session = Table(
|
||||
"frontend_session",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, unique=True),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column('session_cookie', String(32), nullable=False, unique=True),
|
||||
Column("expires", TIMESTAMP, nullable=False),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class PermissionBits(Enum):
|
||||
PermUser = 1
|
||||
PermMod = 2
|
||||
PermSysAdmin = 4
|
||||
|
||||
class UserData(BaseData):
|
||||
def create_user(self, username: str = None, email: str = None, password: str = None) -> Optional[int]:
|
||||
|
||||
if email is None:
|
||||
permission = None
|
||||
else:
|
||||
permission = 0
|
||||
|
||||
sql = aime_user.insert().values(username=username, email=email, password=password, permissions=permission)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def reset_autoincrement(self, ai_value: int) -> None:
|
||||
# Didn't feel like learning how to do this the right way
|
||||
# if somebody wants a free PR go nuts I guess
|
||||
sql = f"ALTER TABLE aime_user AUTO_INCREMENT={ai_value}"
|
||||
self.execute(sql)
|
14
core/data/schema/versions/SDDT_1_rollback.sql
Normal file
14
core/data/schema/versions/SDDT_1_rollback.sql
Normal file
@ -0,0 +1,14 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechBasicHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechAdvancedHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechExpertHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechMasterHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechLunaticHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleBasicHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleAdvancedHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleExpertHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleMasterHighScore int;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleLunaticHighScore int;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
14
core/data/schema/versions/SDDT_2_upgrade.sql
Normal file
14
core/data/schema/versions/SDDT_2_upgrade.sql
Normal file
@ -0,0 +1,14 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechBasicHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechAdvancedHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechExpertHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechMasterHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumTechLunaticHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleBasicHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleAdvancedHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleExpertHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleMasterHighScore bigint;
|
||||
ALTER TABLE ongeki_profile_data MODIFY COLUMN sumBattleLunaticHighScore bigint;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
3
core/data/schema/versions/SDFE_1_rollback.sql
Normal file
3
core/data/schema/versions/SDFE_1_rollback.sql
Normal file
@ -0,0 +1,3 @@
|
||||
UPDATE wacca_score_stageup SET version = 2 WHERE version = 3;
|
||||
UPDATE wacca_score_stageup SET version = 3 WHERE version = 4;
|
||||
ALTER TABLE wacca_score_stageup CHANGE version season int(11) DEFAULT NULL NULL;
|
16
core/data/schema/versions/SDFE_2_rollback.sql
Normal file
16
core/data/schema/versions/SDFE_2_rollback.sql
Normal file
@ -0,0 +1,16 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
ALTER TABLE wacca_profile ADD season int(11) NOT NULL;
|
||||
ALTER TABLE wacca_profile ADD playcount_stageup_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD playcount_multi_coop_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD playcount_multi_vs_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD playcount_single_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD xp_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD wp_season int(11) NULL;
|
||||
ALTER TABLE wacca_profile ADD wp_spent_season int(11) NULL;
|
||||
ALTER TABLE wacca_item ADD use_count_season int(11) NULL;
|
||||
|
||||
ALTER TABLE wacca_profile DROP COLUMN gate_tutorial_flags;
|
||||
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
3
core/data/schema/versions/SDFE_2_upgrade.sql
Normal file
3
core/data/schema/versions/SDFE_2_upgrade.sql
Normal file
@ -0,0 +1,3 @@
|
||||
ALTER TABLE wacca_score_stageup CHANGE season version int(11) DEFAULT NULL NULL;
|
||||
UPDATE wacca_score_stageup SET version = 4 WHERE version = 3;
|
||||
UPDATE wacca_score_stageup SET version = 3 WHERE version = 2;
|
15
core/data/schema/versions/SDFE_3_upgrade.sql
Normal file
15
core/data/schema/versions/SDFE_3_upgrade.sql
Normal file
@ -0,0 +1,15 @@
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
ALTER TABLE wacca_profile DROP COLUMN season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN playcount_stageup_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN playcount_multi_coop_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN playcount_multi_vs_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN playcount_single_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN xp_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN wp_season;
|
||||
ALTER TABLE wacca_profile DROP COLUMN wp_spent_season;
|
||||
ALTER TABLE wacca_item DROP COLUMN use_count_season;
|
||||
|
||||
ALTER TABLE wacca_profile ADD gate_tutorial_flags JSON NULL;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
Reference in New Issue
Block a user