From aba84539c3c2df05f67521c0f8968002b34c2be0 Mon Sep 17 00:00:00 2001 From: kiyreload27 Date: Sun, 28 Dec 2025 17:56:01 +0000 Subject: [PATCH] feat: Implement database management, main window and card view GUI, and a database debug script, removing `verify_fix.py`. --- db/db_queries.py | 46 ++++++++++++++++++++++++++++++++++++++++++++-- debug_db.py | 42 ++++++++++++++++++++++++++++++++++++++++++ gui/card_view.py | 9 ++++++++- gui/main_window.py | 4 +++- verify_fix.py | 33 --------------------------------- 5 files changed, 97 insertions(+), 37 deletions(-) create mode 100644 debug_db.py delete mode 100644 verify_fix.py diff --git a/db/db_queries.py b/db/db_queries.py index d952e0c..a1b4e4f 100644 --- a/db/db_queries.py +++ b/db/db_queries.py @@ -103,6 +103,9 @@ def check_for_updates(): # Or just check inequality. If different, try to update. if db_version != VERSION: sync_from_seed(bundled_seed_path) + + # Always ensure data integrity + cleanup_orphaned_data() except Exception as e: print(f"Update check failed: {e}") @@ -552,7 +555,12 @@ def get_owned_count(): """Get count of owned cards""" conn = get_conn() cur = conn.cursor() - cur.execute("SELECT COUNT(*) FROM owned_cards") + # Use JOIN to ensure only valid cards are counted + cur.execute(""" + SELECT COUNT(*) + FROM owned_cards oc + JOIN support_cards sc ON oc.card_id = sc.card_id + """) count = cur.fetchone()[0] conn.close() return count @@ -692,7 +700,12 @@ def get_database_stats(): cur.execute("SELECT COUNT(*) FROM support_effects") stats['total_effects'] = cur.fetchone()[0] - cur.execute("SELECT COUNT(*) FROM owned_cards") + # Use JOIN to ensure only valid cards are counted + cur.execute(""" + SELECT COUNT(*) + FROM owned_cards oc + JOIN support_cards sc ON oc.card_id = sc.card_id + """) stats['owned_cards'] = cur.fetchone()[0] cur.execute("SELECT COUNT(*) FROM user_decks") @@ -701,6 +714,35 @@ def get_database_stats(): conn.close() return stats +def cleanup_orphaned_data(): + """Remove references to non-existent cards in user data tables""" + print("Cleaning up orphaned database records...") + conn = get_conn() + cur = conn.cursor() + + try: + # 1. Clean owned_cards + cur.execute(""" + DELETE FROM owned_cards + WHERE card_id NOT IN (SELECT card_id FROM support_cards) + """) + if cur.rowcount > 0: + print(f"Removed {cur.rowcount} orphaned owned card records.") + + # 2. Clean deck_slots + cur.execute(""" + DELETE FROM deck_slots + WHERE card_id NOT IN (SELECT card_id FROM support_cards) + """) + if cur.rowcount > 0: + print(f"Removed {cur.rowcount} orphaned deck slot records.") + + conn.commit() + except Exception as e: + print(f"Cleanup failed: {e}") + finally: + conn.close() + # ============================================ # Skill Search Queries # ============================================ diff --git a/debug_db.py b/debug_db.py new file mode 100644 index 0000000..4755615 --- /dev/null +++ b/debug_db.py @@ -0,0 +1,42 @@ +import sqlite3 +import os + +def debug_db(): + db_path = "database/umamusume.db" + if not os.path.exists(db_path): + print(f"Database not found at {db_path}") + return + + conn = sqlite3.connect(db_path) + cur = conn.cursor() + + print("--- Database Debug ---") + + cur.execute("SELECT COUNT(*) FROM support_cards") + print(f"Total support cards: {cur.fetchone()[0]}") + + cur.execute("SELECT COUNT(*) FROM owned_cards") + owned_count = cur.fetchone()[0] + print(f"Owned cards count: {owned_count}") + + cur.execute(""" + SELECT oc.card_id, sc.name + FROM owned_cards oc + LEFT JOIN support_cards sc ON oc.card_id = sc.card_id + """) + rows = cur.fetchall() + + print("\nOwned cards details:") + for card_id, name in rows: + print(f" ID: {card_id}, Name: {name}") + + orphaned = [row[0] for row in rows if row[1] is None] + if orphaned: + print(f"\nFound {len(orphaned)} orphaned owned cards (Card IDs: {orphaned})") + else: + print("\nNo orphaned owned cards found.") + + conn.close() + +if __name__ == "__main__": + debug_db() diff --git a/gui/card_view.py b/gui/card_view.py index b2d02f8..3d14456 100644 --- a/gui/card_view.py +++ b/gui/card_view.py @@ -27,9 +27,10 @@ from gui.theme import ( class CardListFrame(ttk.Frame): """Frame containing card list with search/filter, ownership, and details panel""" - def __init__(self, parent, on_card_selected_callback=None): + def __init__(self, parent, on_card_selected_callback=None, on_stats_updated_callback=None): super().__init__(parent) self.on_card_selected = on_card_selected_callback + self.on_stats_updated = on_stats_updated_callback self.cards = [] self.current_card_id = None self.card_image = None # Keep reference to prevent garbage collection @@ -38,6 +39,8 @@ class CardListFrame(ttk.Frame): # Create main layout self.create_widgets() self.load_cards() + + def create_widgets(self): """Create the card list interface""" @@ -415,6 +418,10 @@ class CardListFrame(ttk.Frame): level = int(self.level_var.get()) set_card_owned(self.current_card_id, owned, level) self.filter_cards() # Refresh list to update owned markers + + # Notify parent to refresh stats + if self.on_stats_updated: + self.on_stats_updated() def update_level_buttons(self, rarity, max_level): """Update quick level buttons based on rarity/max level""" diff --git a/gui/main_window.py b/gui/main_window.py index 99cd97f..a6378a5 100644 --- a/gui/main_window.py +++ b/gui/main_window.py @@ -147,7 +147,9 @@ class MainWindow: def create_tabs(self): """Create all tab frames""" # Card List Tab - self.card_frame = CardListFrame(self.notebook, on_card_selected_callback=self.on_card_selected) + self.card_frame = CardListFrame(self.notebook, + on_card_selected_callback=self.on_card_selected, + on_stats_updated_callback=self.refresh_stats) self.notebook.add(self.card_frame, text=" 📋 Card List ") # Effects Tab diff --git a/verify_fix.py b/verify_fix.py deleted file mode 100644 index 131dddc..0000000 --- a/verify_fix.py +++ /dev/null @@ -1,33 +0,0 @@ - -import sqlite3 -import os -import sys - -# Add current dir to path to import utils -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from utils import resolve_image_path - -DB_PATH = r"y:\Keith\umamusuma card application\database\umamusume.db" -print(f"Checking DB at: {DB_PATH}") - -try: - conn = sqlite3.connect(DB_PATH) - cur = conn.cursor() - cur.execute("SELECT card_id, name, image_path FROM support_cards LIMIT 5") - rows = cur.fetchall() - - print("\nVerifying Path Resolution:") - for row in rows: - card_id, name, original_path = row - resolved = resolve_image_path(original_path) - exists = os.path.exists(resolved) if resolved else False - - print(f"Card: {name}") - print(f" Original: {original_path}") - print(f" Resolved: {resolved}") - print(f" Exists: {exists}") - print("-" * 50) - - conn.close() -except Exception as e: - print(f"Error: {e}")