From 41c9e254e5c825f19bdb143f961b8e207d92ef83 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 4 Nov 2024 16:55:26 +0000 Subject: [PATCH] - Initial database for pokemon_forms is in and sorted. - Updated the list view to auto populate on boot --- database/__init__.py | 0 database/db_controller.py | 98 ++++++++++++++++++++++++++++++++++++ db.py | 2 + main.py | 4 +- ui/main_window_controller.py | 11 +++- ui/main_window_view.py | 12 ++--- utility/functions.py | 4 ++ 7 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 database/__init__.py create mode 100644 database/db_controller.py create mode 100644 db.py diff --git a/database/__init__.py b/database/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/database/db_controller.py b/database/db_controller.py new file mode 100644 index 0000000..08e4ba1 --- /dev/null +++ b/database/db_controller.py @@ -0,0 +1,98 @@ +import sqlite3 +import threading +import json + +class DBController: + def __init__(self, db_path=':memory:', max_connections=10): + self.db_path = db_path + self.lock = threading.Lock() + self.conn = sqlite3.connect(db_path, check_same_thread=False) + self.conn.row_factory = sqlite3.Row + self.cursor = self.conn.cursor() + self.init_database() + + def init_database(self): + disk_conn = sqlite3.connect('pokemon_forms.db') + disk_cursor = disk_conn.cursor() + + # Create tables in the file-based database + self.create_pokemon_forms_table(disk_cursor) + + # Commit changes to the file-based database + disk_conn.commit() + + # Copy the file-based database to the in-memory database + disk_conn.backup(self.conn) + + # Close the file-based database connection + disk_conn.close() + + def save_changes(self): + with self.lock: + # Count the number of records before backup for verification + self.cursor.execute('SELECT COUNT(*) FROM pokemon_forms') + count = self.cursor.fetchone()[0] + print(f"Records in memory before backup: {count}") + + # Back up the master connection to disk + disk_conn = sqlite3.connect('pokemon_forms.db') + with disk_conn: + self.conn.backup(disk_conn) + disk_conn.close() + + def close(self): + self.save_changes() + self.conn.close() + + def create_pokemon_forms_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS pokemon_forms ( + PFIC TEXT PRIMARY KEY, + data JSON NOT NULL + ) + ''') + + def add_pokemon_form(self, pfic, name, form_name, national_dex, generation, sprite_url): + data = { + "name": name, + "form_name": form_name, + "national_dex": national_dex, + "generation": generation, + "sprite_url": sprite_url, + "is_baby_form": False, + "storable_in_home": True, # Example additional field + } + + with self.lock: + self.cursor.execute(''' + INSERT OR REPLACE INTO pokemon_forms (PFIC, data) VALUES (?, ?) + ''', (pfic, json.dumps(data))) + self.conn.commit() + print(f"Added: {pfic}, {name}") + + def get_pokemon_details(self, pfic): + self.cursor.execute(''' + SELECT JSON_EXTRACT(data, '$.name') AS name, + JSON_EXTRACT(data, '$.form_name') AS form_name, + JSON_EXTRACT(data, '$.national_dex') AS national_dex, + JSON_EXTRACT(data, '$.generation') AS generation, + JSON_EXTRACT(data, '$.is_baby_form') AS is_baby_form, + FROM pokemon_forms + WHERE PFIC = ? + ''', (pfic,)) + results = self.cursor.fetchone() + return dict(results) + + def get_list_of_pokemon_forms(self): + self.cursor.execute(''' + SELECT JSON_EXTRACT(data, '$.name') AS name, + JSON_EXTRACT(data, '$.form_name') AS form_name, + JSON_EXTRACT(data, '$.national_dex') AS national_dex, + JSON_EXTRACT(data, '$.generation') AS generation, + JSON_EXTRACT(data, '$.is_baby_form') AS is_baby_form, + PFIC as pfic + FROM pokemon_forms + ''',) + results = self.cursor.fetchall() + + return [dict(row) for row in results] diff --git a/db.py b/db.py new file mode 100644 index 0000000..17dda80 --- /dev/null +++ b/db.py @@ -0,0 +1,2 @@ +from database.db_controller import DBController +db = DBController() \ No newline at end of file diff --git a/main.py b/main.py index 7dd806a..7eb5ed4 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ from PyQt6 import QtWidgets from ui.main_window_view import PokemonUI from cache import cache +from db import db def main(): import sys @@ -20,4 +21,5 @@ if __name__ == "__main__": main() finally: # Ensure the cache is closed at the end of the application - cache.close() \ No newline at end of file + cache.close() + db.close() \ No newline at end of file diff --git a/ui/main_window_controller.py b/ui/main_window_controller.py index 30e1919..90b301e 100644 --- a/ui/main_window_controller.py +++ b/ui/main_window_controller.py @@ -4,6 +4,8 @@ from PyQt6.QtGui import QAction from ui.workers import GatherPokemonFormsWorker +from db import db + class MainWindowController: def __init__(self, view): self.view = view @@ -16,7 +18,7 @@ class MainWindowController: def initialize_pokemon_list(self, data): self.pokemon_data_cache = data - self.view.update_pokemon_list(data) + self.view.update_pokemon_forms(data) def filter_pokemon_list(self): self.filter_timer.start() @@ -48,7 +50,7 @@ class MainWindowController: filtered_data.append((pfic, display_name)) # Update the view with the filtered data - self.view.update_pokemon_list(filtered_data) + self.view.update_pokemon_forms(filtered_data) def show_pokemon_context_menu(self, position): item = self.view.pokemon_list.itemAt(position) @@ -86,8 +88,13 @@ class MainWindowController: def on_forms_gathered(self, data): # This method will be called in the main thread when the worker finishes # Update the UI with the gathered forms + for pokemon in data: + db.add_pokemon_form(pokemon["pfic"], pokemon["name"], pokemon["form_name"], pokemon["national_dex"], pokemon["generation"], pokemon["sprite_url"]) + self.pokemon_data_cache = data self.view.update_pokemon_forms(data) + db.save_changes() + def gather_home_storage_info(self): pass diff --git a/ui/main_window_view.py b/ui/main_window_view.py index b910d47..5862b6f 100644 --- a/ui/main_window_view.py +++ b/ui/main_window_view.py @@ -6,11 +6,15 @@ from PyQt6.QtCore import Qt, QSize, QTimer, QMetaObject from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction from .main_window_controller import MainWindowController +from db import db + class PokemonUI(QWidget): def __init__(self, parent=None): super().__init__(parent) self.controller = MainWindowController(self) self.setup_ui() + data = db.get_list_of_pokemon_forms() + self.controller.initialize_pokemon_list(data) def setup_ui(self): main_layout = QVBoxLayout(self) @@ -209,14 +213,6 @@ class PokemonUI(QWidget): #self.load_exclusive_sets() - def update_pokemon_list(self, data): - self.pokemon_list.clear() - - for pfic, display_name in data: - item = QListWidgetItem(display_name) - item.setData(Qt.ItemDataRole.UserRole, pfic) - self.pokemon_list.addItem(item) - def update_pokemon_forms(self, data): self.pokemon_list.clear() diff --git a/utility/functions.py b/utility/functions.py index b368391..d917bb4 100644 --- a/utility/functions.py +++ b/utility/functions.py @@ -4,6 +4,10 @@ import unicodedata def format_pokemon_id(national_dex: int, region_code: int, form_index: int, gender_code: int) -> str: return f"{national_dex:04d}-{region_code:02d}-{form_index:03d}-{gender_code}" +def parse_pfic(pfic): + parts = pfic.split('-') + return tuple(int(part) if part.isdigit() else part for part in parts) + def compare_pokemon_forms(a, b): if a == None or b == None: return False