diff --git a/src/conf.py b/src/conf.py
index 35beca2..1122676 100644
--- a/src/conf.py
+++ b/src/conf.py
@@ -89,6 +89,7 @@ class PostgreSqlDb(BaseModel):
username: str
password: str
ssl_mode: SSLMode = SSLMode.PREFER
+ timeout: int = 10
class Project(BaseModel):
diff --git a/src/ui/PostgreSqlConfigDialog.py b/src/ui/PostgreSqlConfigDialog.py
index 8c90bd1..ad0b458 100644
--- a/src/ui/PostgreSqlConfigDialog.py
+++ b/src/ui/PostgreSqlConfigDialog.py
@@ -19,8 +19,14 @@ class DatabaseTestThread(QThread):
def run(self):
"""Führt den Datenbanktest in einem separaten Thread aus."""
try:
- uri = f"postgresql://{self.connection_data['username']}:{self.connection_data['password']}@{self.connection_data['host']}:{self.connection_data['port']}/{self.connection_data['database']}"
-
+ timeout = self.connection_data.get("timeout", 10)
+ uri = (
+ f"postgresql://{self.connection_data['username']}:{self.connection_data['password']}"
+ f"@{self.connection_data['host']}:{self.connection_data['port']}"
+ f"/{self.connection_data['database']}"
+ f"?connect_timeout={timeout}"
+ )
+
# Datenbankverbindung testen
r = pl.read_database_uri(
query="SELECT 1",
@@ -106,6 +112,7 @@ class PostgreSqlConfigDialog(QDialog):
self.ui.usernameEdit.setText(data.get("username", ""))
self.ui.passwordEdit.setText(data.get("password", ""))
self.ui.sslModeComboBox.setCurrentText(data.get("ssl_mode", "prefer"))
+ self.ui.timeoutSpinBox.setValue(data.get("timeout", 10))
def get_data(self):
"""Gibt die eingegebenen Daten zurück."""
@@ -126,4 +133,5 @@ class PostgreSqlConfigDialog(QDialog):
"username": self.ui.usernameEdit.text().strip(),
"password": self.ui.passwordEdit.text(), # Passwort kann leer sein
"ssl_mode": self.ui.sslModeComboBox.currentText(),
+ "timeout": self.ui.timeoutSpinBox.value(),
}
diff --git a/src/ui/PostgreSqlConfigDialog.ui b/src/ui/PostgreSqlConfigDialog.ui
index 20fdafe..0a8de8f 100644
--- a/src/ui/PostgreSqlConfigDialog.ui
+++ b/src/ui/PostgreSqlConfigDialog.ui
@@ -138,7 +138,27 @@
+ -
+
+
+ Timeout (s):
+
+
+
-
+
+
+ 1
+
+
+ 300
+
+
+ 10
+
+
+
+ -
Verbindung testen
diff --git a/src/ui/PostgreSqlConfigDialog_ui.py b/src/ui/PostgreSqlConfigDialog_ui.py
index 0443022..f3cccff 100644
--- a/src/ui/PostgreSqlConfigDialog_ui.py
+++ b/src/ui/PostgreSqlConfigDialog_ui.py
@@ -1,156 +1,170 @@
-# -*- coding: utf-8 -*-
-
-################################################################################
-## Form generated from reading UI file 'PostgreSqlConfigDialog.ui'
-##
-## Created by: Qt User Interface Compiler version 6.9.1
-##
-## WARNING! All changes made in this file will be lost when recompiling UI file!
-################################################################################
-
-from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
- QMetaObject, QObject, QPoint, QRect,
- QSize, QTime, QUrl, Qt)
-from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
- QFont, QFontDatabase, QGradient, QIcon,
- QImage, QKeySequence, QLinearGradient, QPainter,
- QPalette, QPixmap, QRadialGradient, QTransform)
-from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog,
- QDialogButtonBox, QFormLayout, QLabel, QLineEdit,
- QPushButton, QSizePolicy, QSpinBox, QVBoxLayout,
- QWidget)
-
-class Ui_PostgreSqlConfigDialog(object):
- def setupUi(self, PostgreSqlConfigDialog):
- if not PostgreSqlConfigDialog.objectName():
- PostgreSqlConfigDialog.setObjectName(u"PostgreSqlConfigDialog")
- PostgreSqlConfigDialog.resize(397, 268)
- PostgreSqlConfigDialog.setModal(True)
- self.verticalLayout = QVBoxLayout(PostgreSqlConfigDialog)
- self.verticalLayout.setObjectName(u"verticalLayout")
- self.formLayout = QFormLayout()
- self.formLayout.setObjectName(u"formLayout")
- self.nameLabel = QLabel(PostgreSqlConfigDialog)
- self.nameLabel.setObjectName(u"nameLabel")
-
- self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.nameLabel)
-
- self.nameEdit = QLineEdit(PostgreSqlConfigDialog)
- self.nameEdit.setObjectName(u"nameEdit")
-
- self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.nameEdit)
-
- self.hostLabel = QLabel(PostgreSqlConfigDialog)
- self.hostLabel.setObjectName(u"hostLabel")
-
- self.formLayout.setWidget(1, QFormLayout.ItemRole.LabelRole, self.hostLabel)
-
- self.hostEdit = QLineEdit(PostgreSqlConfigDialog)
- self.hostEdit.setObjectName(u"hostEdit")
-
- self.formLayout.setWidget(1, QFormLayout.ItemRole.FieldRole, self.hostEdit)
-
- self.portLabel = QLabel(PostgreSqlConfigDialog)
- self.portLabel.setObjectName(u"portLabel")
-
- self.formLayout.setWidget(2, QFormLayout.ItemRole.LabelRole, self.portLabel)
-
- self.portSpinBox = QSpinBox(PostgreSqlConfigDialog)
- self.portSpinBox.setObjectName(u"portSpinBox")
- self.portSpinBox.setMinimum(1)
- self.portSpinBox.setMaximum(65535)
- self.portSpinBox.setValue(5432)
-
- self.formLayout.setWidget(2, QFormLayout.ItemRole.FieldRole, self.portSpinBox)
-
- self.databaseLabel = QLabel(PostgreSqlConfigDialog)
- self.databaseLabel.setObjectName(u"databaseLabel")
-
- self.formLayout.setWidget(3, QFormLayout.ItemRole.LabelRole, self.databaseLabel)
-
- self.databaseEdit = QLineEdit(PostgreSqlConfigDialog)
- self.databaseEdit.setObjectName(u"databaseEdit")
-
- self.formLayout.setWidget(3, QFormLayout.ItemRole.FieldRole, self.databaseEdit)
-
- self.usernameLabel = QLabel(PostgreSqlConfigDialog)
- self.usernameLabel.setObjectName(u"usernameLabel")
-
- self.formLayout.setWidget(4, QFormLayout.ItemRole.LabelRole, self.usernameLabel)
-
- self.usernameEdit = QLineEdit(PostgreSqlConfigDialog)
- self.usernameEdit.setObjectName(u"usernameEdit")
-
- self.formLayout.setWidget(4, QFormLayout.ItemRole.FieldRole, self.usernameEdit)
-
- self.passwordLabel = QLabel(PostgreSqlConfigDialog)
- self.passwordLabel.setObjectName(u"passwordLabel")
-
- self.formLayout.setWidget(5, QFormLayout.ItemRole.LabelRole, self.passwordLabel)
-
- self.passwordEdit = QLineEdit(PostgreSqlConfigDialog)
- self.passwordEdit.setObjectName(u"passwordEdit")
- self.passwordEdit.setEchoMode(QLineEdit.EchoMode.Password)
-
- self.formLayout.setWidget(5, QFormLayout.ItemRole.FieldRole, self.passwordEdit)
-
- self.sslModeLabel = QLabel(PostgreSqlConfigDialog)
- self.sslModeLabel.setObjectName(u"sslModeLabel")
-
- self.formLayout.setWidget(6, QFormLayout.ItemRole.LabelRole, self.sslModeLabel)
-
- self.sslModeComboBox = QComboBox(PostgreSqlConfigDialog)
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.addItem("")
- self.sslModeComboBox.setObjectName(u"sslModeComboBox")
-
- self.formLayout.setWidget(6, QFormLayout.ItemRole.FieldRole, self.sslModeComboBox)
-
- self.testConnectionButton = QPushButton(PostgreSqlConfigDialog)
- self.testConnectionButton.setObjectName(u"testConnectionButton")
-
- self.formLayout.setWidget(7, QFormLayout.ItemRole.FieldRole, self.testConnectionButton)
-
-
- self.verticalLayout.addLayout(self.formLayout)
-
- self.buttonBox = QDialogButtonBox(PostgreSqlConfigDialog)
- self.buttonBox.setObjectName(u"buttonBox")
- self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
- self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok)
- self.buttonBox.setCenterButtons(True)
-
- self.verticalLayout.addWidget(self.buttonBox)
-
-
- self.retranslateUi(PostgreSqlConfigDialog)
- self.buttonBox.accepted.connect(PostgreSqlConfigDialog.accept)
- self.buttonBox.rejected.connect(PostgreSqlConfigDialog.reject)
-
- QMetaObject.connectSlotsByName(PostgreSqlConfigDialog)
- # setupUi
-
- def retranslateUi(self, PostgreSqlConfigDialog):
- PostgreSqlConfigDialog.setWindowTitle(QCoreApplication.translate("PostgreSqlConfigDialog", u"PostgreSQL Datenbank Konfiguration", None))
- self.nameLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Name:", None))
- self.hostLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Host:", None))
- self.hostEdit.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"localhost", None))
- self.portLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Port:", None))
- self.databaseLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Datenbank:", None))
- self.usernameLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Benutzername:", None))
- self.passwordLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Passwort:", None))
- self.sslModeLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"SSL-Modus:", None))
- self.sslModeComboBox.setItemText(0, QCoreApplication.translate("PostgreSqlConfigDialog", u"disable", None))
- self.sslModeComboBox.setItemText(1, QCoreApplication.translate("PostgreSqlConfigDialog", u"allow", None))
- self.sslModeComboBox.setItemText(2, QCoreApplication.translate("PostgreSqlConfigDialog", u"prefer", None))
- self.sslModeComboBox.setItemText(3, QCoreApplication.translate("PostgreSqlConfigDialog", u"require", None))
- self.sslModeComboBox.setItemText(4, QCoreApplication.translate("PostgreSqlConfigDialog", u"verify-ca", None))
- self.sslModeComboBox.setItemText(5, QCoreApplication.translate("PostgreSqlConfigDialog", u"verify-full", None))
-
- self.testConnectionButton.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Verbindung testen", None))
- # retranslateUi
-
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'PostgreSqlConfigDialog.ui'
+##
+## Created by: Qt User Interface Compiler version 6.10.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog,
+ QDialogButtonBox, QFormLayout, QLabel, QLineEdit,
+ QPushButton, QSizePolicy, QSpinBox, QVBoxLayout,
+ QWidget)
+
+class Ui_PostgreSqlConfigDialog(object):
+ def setupUi(self, PostgreSqlConfigDialog):
+ if not PostgreSqlConfigDialog.objectName():
+ PostgreSqlConfigDialog.setObjectName(u"PostgreSqlConfigDialog")
+ PostgreSqlConfigDialog.resize(397, 268)
+ PostgreSqlConfigDialog.setModal(True)
+ self.verticalLayout = QVBoxLayout(PostgreSqlConfigDialog)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.formLayout = QFormLayout()
+ self.formLayout.setObjectName(u"formLayout")
+ self.nameLabel = QLabel(PostgreSqlConfigDialog)
+ self.nameLabel.setObjectName(u"nameLabel")
+
+ self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.nameLabel)
+
+ self.nameEdit = QLineEdit(PostgreSqlConfigDialog)
+ self.nameEdit.setObjectName(u"nameEdit")
+
+ self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.nameEdit)
+
+ self.hostLabel = QLabel(PostgreSqlConfigDialog)
+ self.hostLabel.setObjectName(u"hostLabel")
+
+ self.formLayout.setWidget(1, QFormLayout.ItemRole.LabelRole, self.hostLabel)
+
+ self.hostEdit = QLineEdit(PostgreSqlConfigDialog)
+ self.hostEdit.setObjectName(u"hostEdit")
+
+ self.formLayout.setWidget(1, QFormLayout.ItemRole.FieldRole, self.hostEdit)
+
+ self.portLabel = QLabel(PostgreSqlConfigDialog)
+ self.portLabel.setObjectName(u"portLabel")
+
+ self.formLayout.setWidget(2, QFormLayout.ItemRole.LabelRole, self.portLabel)
+
+ self.portSpinBox = QSpinBox(PostgreSqlConfigDialog)
+ self.portSpinBox.setObjectName(u"portSpinBox")
+ self.portSpinBox.setMinimum(1)
+ self.portSpinBox.setMaximum(65535)
+ self.portSpinBox.setValue(5432)
+
+ self.formLayout.setWidget(2, QFormLayout.ItemRole.FieldRole, self.portSpinBox)
+
+ self.databaseLabel = QLabel(PostgreSqlConfigDialog)
+ self.databaseLabel.setObjectName(u"databaseLabel")
+
+ self.formLayout.setWidget(3, QFormLayout.ItemRole.LabelRole, self.databaseLabel)
+
+ self.databaseEdit = QLineEdit(PostgreSqlConfigDialog)
+ self.databaseEdit.setObjectName(u"databaseEdit")
+
+ self.formLayout.setWidget(3, QFormLayout.ItemRole.FieldRole, self.databaseEdit)
+
+ self.usernameLabel = QLabel(PostgreSqlConfigDialog)
+ self.usernameLabel.setObjectName(u"usernameLabel")
+
+ self.formLayout.setWidget(4, QFormLayout.ItemRole.LabelRole, self.usernameLabel)
+
+ self.usernameEdit = QLineEdit(PostgreSqlConfigDialog)
+ self.usernameEdit.setObjectName(u"usernameEdit")
+
+ self.formLayout.setWidget(4, QFormLayout.ItemRole.FieldRole, self.usernameEdit)
+
+ self.passwordLabel = QLabel(PostgreSqlConfigDialog)
+ self.passwordLabel.setObjectName(u"passwordLabel")
+
+ self.formLayout.setWidget(5, QFormLayout.ItemRole.LabelRole, self.passwordLabel)
+
+ self.passwordEdit = QLineEdit(PostgreSqlConfigDialog)
+ self.passwordEdit.setObjectName(u"passwordEdit")
+ self.passwordEdit.setEchoMode(QLineEdit.EchoMode.Password)
+
+ self.formLayout.setWidget(5, QFormLayout.ItemRole.FieldRole, self.passwordEdit)
+
+ self.sslModeLabel = QLabel(PostgreSqlConfigDialog)
+ self.sslModeLabel.setObjectName(u"sslModeLabel")
+
+ self.formLayout.setWidget(6, QFormLayout.ItemRole.LabelRole, self.sslModeLabel)
+
+ self.sslModeComboBox = QComboBox(PostgreSqlConfigDialog)
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.addItem("")
+ self.sslModeComboBox.setObjectName(u"sslModeComboBox")
+
+ self.formLayout.setWidget(6, QFormLayout.ItemRole.FieldRole, self.sslModeComboBox)
+
+ self.timeoutLabel = QLabel(PostgreSqlConfigDialog)
+ self.timeoutLabel.setObjectName(u"timeoutLabel")
+
+ self.formLayout.setWidget(7, QFormLayout.ItemRole.LabelRole, self.timeoutLabel)
+
+ self.timeoutSpinBox = QSpinBox(PostgreSqlConfigDialog)
+ self.timeoutSpinBox.setObjectName(u"timeoutSpinBox")
+ self.timeoutSpinBox.setMinimum(1)
+ self.timeoutSpinBox.setMaximum(300)
+ self.timeoutSpinBox.setValue(10)
+
+ self.formLayout.setWidget(7, QFormLayout.ItemRole.FieldRole, self.timeoutSpinBox)
+
+ self.testConnectionButton = QPushButton(PostgreSqlConfigDialog)
+ self.testConnectionButton.setObjectName(u"testConnectionButton")
+
+ self.formLayout.setWidget(8, QFormLayout.ItemRole.FieldRole, self.testConnectionButton)
+
+
+ self.verticalLayout.addLayout(self.formLayout)
+
+ self.buttonBox = QDialogButtonBox(PostgreSqlConfigDialog)
+ self.buttonBox.setObjectName(u"buttonBox")
+ self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
+ self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok)
+ self.buttonBox.setCenterButtons(True)
+
+ self.verticalLayout.addWidget(self.buttonBox)
+
+
+ self.retranslateUi(PostgreSqlConfigDialog)
+ self.buttonBox.accepted.connect(PostgreSqlConfigDialog.accept)
+ self.buttonBox.rejected.connect(PostgreSqlConfigDialog.reject)
+
+ QMetaObject.connectSlotsByName(PostgreSqlConfigDialog)
+ # setupUi
+
+ def retranslateUi(self, PostgreSqlConfigDialog):
+ PostgreSqlConfigDialog.setWindowTitle(QCoreApplication.translate("PostgreSqlConfigDialog", u"PostgreSQL Datenbank Konfiguration", None))
+ self.nameLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Name:", None))
+ self.hostLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Host:", None))
+ self.hostEdit.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"localhost", None))
+ self.portLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Port:", None))
+ self.databaseLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Datenbank:", None))
+ self.usernameLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Benutzername:", None))
+ self.passwordLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Passwort:", None))
+ self.sslModeLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"SSL-Modus:", None))
+ self.sslModeComboBox.setItemText(0, QCoreApplication.translate("PostgreSqlConfigDialog", u"disable", None))
+ self.sslModeComboBox.setItemText(1, QCoreApplication.translate("PostgreSqlConfigDialog", u"allow", None))
+ self.sslModeComboBox.setItemText(2, QCoreApplication.translate("PostgreSqlConfigDialog", u"prefer", None))
+ self.sslModeComboBox.setItemText(3, QCoreApplication.translate("PostgreSqlConfigDialog", u"require", None))
+ self.sslModeComboBox.setItemText(4, QCoreApplication.translate("PostgreSqlConfigDialog", u"verify-ca", None))
+ self.sslModeComboBox.setItemText(5, QCoreApplication.translate("PostgreSqlConfigDialog", u"verify-full", None))
+
+ self.timeoutLabel.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Timeout (s):", None))
+ self.testConnectionButton.setText(QCoreApplication.translate("PostgreSqlConfigDialog", u"Verbindung testen", None))
+ # retranslateUi
+
diff --git a/src/ui/mixins/database.py b/src/ui/mixins/database.py
index 597c88f..c7995de 100644
--- a/src/ui/mixins/database.py
+++ b/src/ui/mixins/database.py
@@ -10,13 +10,35 @@ import logging
from pathlib import Path
import polars as pl
-from PySide6.QtWidgets import QMessageBox
+from PySide6.QtCore import QThread, Signal, Qt
+from PySide6.QtWidgets import QMessageBox, QProgressDialog
from conf import app_settings, TreeNode, XslFile
logger = logging.getLogger(__name__)
+class DatabaseQueryThread(QThread):
+ """Thread für asynchrone Datenbankabfragen."""
+
+ query_completed = Signal(object) # pl.DataFrame
+ query_failed = Signal(str) # Fehlermeldung
+
+ def __init__(self, sql_query, connection_string):
+ super().__init__()
+ self.sql_query = sql_query
+ self.connection_string = connection_string
+
+ def run(self):
+ try:
+ df = pl.read_database_uri(self.sql_query, self.connection_string, engine="connectorx").sort(
+ ["reporttyp_bez", "report_bez", "repfile_bez"]
+ )
+ self.query_completed.emit(df)
+ except Exception as e:
+ self.query_failed.emit(str(e))
+
+
class DatabaseMixin:
"""
Mixin für Datenbank-Operationen.
@@ -31,7 +53,7 @@ class DatabaseMixin:
def on_load_from_fn2_clicked(self):
"""
Wird ausgeführt, wenn der Button "lade aus FN2" geklickt wird.
- Führt SQL-Abfrage aus und aktualisiert die Projekt-Nodes.
+ Startet SQL-Abfrage asynchron mit Fortschrittsdialog.
"""
logger.debug("Button 'lade aus FN2' wurde geklickt!")
@@ -52,29 +74,68 @@ class DatabaseMixin:
QMessageBox.warning(self, "Warnung", "PostgreSQL-Datenbank-Konfiguration nicht gefunden.")
return
- # Führe SQL-Abfrage aus
- df = self._execute_sql_query(db_config)
- if df is None:
+ # SQL-Abfrage und Connection-String vorbereiten
+ sql_query, connection_string = self._prepare_sql_query(db_config)
+ if sql_query is None:
return # Fehler bereits angezeigt
- # Verarbeite die Daten wie in readCsv.py
- new_nodes = self._process_sql_data(df)
+ # Fortschrittsdialog erstellen
+ self._db_progress = QProgressDialog("Verbinde mit Datenbank...", "Abbrechen", 0, 0, self)
+ self._db_progress.setWindowTitle("Datenbank-Abfrage")
+ self._db_progress.setWindowModality(Qt.WindowModal)
+ self._db_progress.setMinimumDuration(0)
- # Merge mit vorhandenen Nodes
- self._merge_nodes_with_existing(new_nodes)
-
- # Speichere die aktualisierten Projekt-Einstellungen
- self._save_project_settings()
-
- # Lade das Projekt neu
- self._load_nodes_to_tree()
-
- # QMessageBox.information(self, "Erfolg", "Daten erfolgreich aus FN2 geladen und Projekt aktualisiert!")
+ # Query-Thread erstellen und starten
+ self._db_query_thread = DatabaseQueryThread(sql_query, connection_string)
+ self._db_query_thread.query_completed.connect(self._on_db_query_completed)
+ self._db_query_thread.query_failed.connect(self._on_db_query_failed)
+ self._db_query_thread.finished.connect(self._cleanup_db_query)
+ self._db_progress.canceled.connect(self._on_db_query_canceled)
+ self._db_query_thread.start()
except Exception as e:
logger.error(f"Fehler beim Laden aus FN2: {e}")
QMessageBox.critical(self, "Fehler", f"Fehler beim Laden aus FN2:\n{str(e)}")
+ def _on_db_query_completed(self, df):
+ """Wird aufgerufen, wenn die Datenbankabfrage erfolgreich war."""
+ # Ignoriere Ergebnis, falls der Benutzer abgebrochen hat
+ if hasattr(self, "_db_progress") and self._db_progress.wasCanceled():
+ return
+
+ try:
+ new_nodes = self._process_sql_data(df)
+ self._merge_nodes_with_existing(new_nodes)
+ self._save_project_settings()
+ self._load_nodes_to_tree()
+ except Exception as e:
+ logger.error(f"Fehler beim Verarbeiten der DB-Daten: {e}")
+ QMessageBox.critical(self, "Fehler", f"Fehler beim Verarbeiten der Daten:\n{str(e)}")
+
+ def _on_db_query_failed(self, error_msg):
+ """Wird aufgerufen, wenn die Datenbankabfrage fehlgeschlagen ist."""
+ if hasattr(self, "_db_progress") and self._db_progress.wasCanceled():
+ return
+
+ error = f"Fehler beim Ausführen der SQL-Abfrage: {error_msg}"
+ logger.error(error)
+ QMessageBox.critical(self, "Fehler", error)
+
+ def _on_db_query_canceled(self):
+ """Wird aufgerufen, wenn der Benutzer die Abfrage abbricht."""
+ logger.info("Datenbankabfrage vom Benutzer abgebrochen")
+
+ def _cleanup_db_query(self):
+ """Räumt nach der Datenbankabfrage auf."""
+ if hasattr(self, "_db_progress"):
+ self._db_progress.canceled.disconnect(self._on_db_query_canceled)
+ self._db_progress.close()
+ self._db_progress.deleteLater()
+ del self._db_progress
+ if hasattr(self, "_db_query_thread"):
+ self._db_query_thread.deleteLater()
+ del self._db_query_thread
+
def _get_database_config(self, db_id):
"""
Holt die Datenbank-Konfiguration anhand der ID.
@@ -90,29 +151,27 @@ class DatabaseMixin:
return db
return None
- def _execute_sql_query(self, db_config):
+ def _prepare_sql_query(self, db_config):
"""
- Führt die SQL-Abfrage aus der data.sql Datei aus.
+ Bereitet SQL-Abfrage und Connection-String vor.
Args:
db_config: PostgreSQL-Datenbank-Konfiguration
Returns:
- pl.DataFrame|None: Die Abfrageergebnisse oder None bei Fehler
+ tuple[str, str]|tuple[None, None]: (sql_query, connection_string) oder (None, None) bei Fehler
"""
try:
- # Lade SQL-Abfrage aus Datei
sql_file_path = Path("src/res/data.sql")
if not sql_file_path.exists():
QMessageBox.critical(self, "Fehler", f"SQL-Datei nicht gefunden: {sql_file_path}")
- return None
+ return None, None
with open(sql_file_path, "r", encoding="utf-8") as f:
sql_query = f.read()
logger.debug(f"SQL-Abfrage geladen: {len(sql_query)} Zeichen")
- # Verbindung zur PostgreSQL-Datenbank herstellen
connection_string = (
"postgresql://"
f"{db_config.username}:"
@@ -121,19 +180,17 @@ class DatabaseMixin:
f"{db_config.port}/"
f"{db_config.database}?"
f"sslmode={db_config.ssl_mode.value}"
+ f"&connect_timeout={db_config.timeout}"
)
logger.info(f"Verbinde zu PostgreSQL: {db_config.host}:{db_config.port}/{db_config.database}")
- df = pl.read_database_uri(sql_query, connection_string, engine="connectorx").sort(
- ["reporttyp_bez", "report_bez", "repfile_bez"]
- )
- return df
+ return sql_query, connection_string
except Exception as e:
- error_msg = f"Fehler beim Ausführen der SQL-Abfrage: {str(e)}"
+ error_msg = f"Fehler beim Vorbereiten der SQL-Abfrage: {str(e)}"
logger.error(error_msg)
QMessageBox.critical(self, "Fehler", error_msg)
- return None
+ return None, None
def _process_sql_data(self, df):
"""