""" Database initialization script for MTG Online backend. Creates all necessary tables matching the SQLAlchemy ORM models for both databases. """ import asyncio from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from sqlalchemy import text from app.core.settings import get_settings async def setup_mtg_online_database(): """Create tables for the mtgonline database.""" settings = get_settings() engine = create_async_engine(settings.MTGO_DATABASE_URL) async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) async with async_session() as session: # Create tables tables = [ """ CREATE TABLE IF NOT EXISTS mtgonline_users ( id SERIAL PRIMARY KEY, username VARCHAR(64) UNIQUE NOT NULL, password_hash VARCHAR(128) NOT NULL, salt VARCHAR(128) NOT NULL, email VARCHAR(255), country VARCHAR(2), real_name VARCHAR(128), avatar_bmp TEXT, privlevel VARCHAR(50) DEFAULT 'User', is_active BOOLEAN DEFAULT TRUE, is_banned BOOLEAN DEFAULT FALSE, ban_reason TEXT, ban_ends TIMESTAMP, vip_status INTEGER DEFAULT 0, vip_expiry TIMESTAMP, creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_decklist_folders ( id SERIAL PRIMARY KEY, owner_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, parent_id INTEGER REFERENCES mtgonline_decklist_folders(id) ON DELETE CASCADE, creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_decklist_files ( id SERIAL PRIMARY KEY, folder_id INTEGER REFERENCES mtgonline_decklist_folders(id) ON DELETE CASCADE, owner_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, content TEXT NOT NULL, format VARCHAR(50) DEFAULT 'native', creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_rooms ( id SERIAL PRIMARY KEY, name VARCHAR(100) UNIQUE NOT NULL, description TEXT, is_password_protected BOOLEAN DEFAULT FALSE, password_hash VARCHAR(128), creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_rooms_gametypes ( id SERIAL PRIMARY KEY, room_id INTEGER REFERENCES mtgonline_rooms(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, description TEXT ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_bans ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE, server_id INTEGER, reason TEXT NOT NULL, moderators VARCHAR(255), ip_address VARCHAR(45), expiration_time TIMESTAMP, active BOOLEAN DEFAULT TRUE, creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_log ( id SERIAL PRIMARY KEY, room_id INTEGER REFERENCES mtgonline_rooms(id) ON DELETE CASCADE, player_id INTEGER REFERENCES mtgonline_users(id) ON DELETE CASCADE, message TEXT NOT NULL, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtgonline_audit ( id SERIAL PRIMARY KEY, admin_id INTEGER REFERENCES mtgonline_users(id) ON DELETE SET NULL, action_type VARCHAR(50) NOT NULL, target_user_id INTEGER REFERENCES mtgonline_users(id) ON DELETE SET NULL, details TEXT, ip_address VARCHAR(45), timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, ] for table_sql in tables: await session.execute(text(table_sql)) # Create indexes indexes = [ "CREATE INDEX IF NOT EXISTS idx_decks_owner ON mtgonline_decklist_files(owner_id);", "CREATE INDEX IF NOT EXISTS idx_decks_folder ON mtgonline_decklist_files(folder_id);", "CREATE INDEX IF NOT EXISTS idx_bans_active ON mtgonline_bans(active);", "CREATE INDEX IF NOT EXISTS idx_log_timestamp ON mtgonline_log(timestamp);", ] for idx_sql in indexes: await session.execute(text(idx_sql)) print("āœ“ All mtgonline tables created") await engine.dispose() async def setup_mtg_data_database(): """Create tables for the mtgdata database.""" settings = get_settings() engine = create_async_engine(settings.MTG_DATABASE_URL) async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) async with async_session() as session: # Create tables tables = [ """ CREATE TABLE IF NOT EXISTS mtg_sets ( id SERIAL PRIMARY KEY, code VARCHAR(10) UNIQUE NOT NULL, name VARCHAR(255), type VARCHAR(100), release_date DATE, base_set_size INTEGER, total_size INTEGER, is_foil_only BOOLEAN, is_non_foil_only BOOLEAN, digital BOOLEAN, icon_svg_url TEXT, parent_code VARCHAR(10), mtgo_code VARCHAR(10), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, """ CREATE TABLE IF NOT EXISTS mtg_cards ( id SERIAL PRIMARY KEY, set_id INTEGER REFERENCES mtg_sets(id) ON DELETE CASCADE, name VARCHAR(255), mana_cost VARCHAR(255), type_line VARCHAR(255), oracle_text TEXT, power VARCHAR(50), toughness VARCHAR(50), rarity VARCHAR(50), layout VARCHAR(50), artist VARCHAR(255), flavor_text TEXT, numbers VARCHAR(100), identifiers TEXT, images TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """, ] for table_sql in tables: await session.execute(text(table_sql)) # Create indexes indexes = [ "CREATE INDEX IF NOT EXISTS idx_mtg_cards_name ON mtg_cards(name);", "CREATE INDEX IF NOT EXISTS idx_mtg_cards_type ON mtg_cards(type_line);", "CREATE INDEX IF NOT EXISTS idx_mtg_cards_rarity ON mtg_cards(rarity);", "CREATE INDEX IF NOT EXISTS idx_mtg_cards_set_id ON mtg_cards(set_id);", ] for idx_sql in indexes: await session.execute(text(idx_sql)) print("āœ“ All mtgdata tables created") await engine.dispose() async def main(): """Main initialization function.""" print("MTG Online Database Initialization") print("=" * 50) # Setup mtgonline database print("\nSetting up mtgonline database...") await setup_mtg_online_database() # Setup mtgdata database print("\nSetting up mtgdata database...") await setup_mtg_data_database() print("\nāœ“ Database initialization complete!") if __name__ == "__main__": asyncio.run(main())