Files
2026-05-21 15:46:41 -04:00

99 lines
3.3 KiB
Python

"""
QThread-based async worker for all database operations.
Emits results/errors via Qt signals so the UI stays responsive.
"""
import time
from PyQt6.QtCore import QThread, pyqtSignal
from app.utils.logger import get_logger
_log = get_logger(__name__)
class QueryWorker(QThread):
"""Execute a SQL query in a background thread."""
finished = pyqtSignal(list, list, int, float) # cols, rows, rowcount, elapsed_sec
error = pyqtSignal(str)
script_done = pyqtSignal(list) # list of (cols, rows, cnt, msg)
def __init__(self, driver, sql: str, is_script: bool = False, parent=None):
super().__init__(parent)
self._driver = driver
self._sql = sql
self._script = is_script
def run(self):
t0 = time.perf_counter()
try:
if self._script:
results = self._driver.execute_script(self._sql)
self.script_done.emit(results)
else:
cols, rows, cnt = self._driver.execute_query(self._sql)
elapsed = time.perf_counter() - t0
_log.debug("Query OK (%.3f s, %d row(s)) SQL: %.200s",
elapsed, cnt, self._sql.replace("\n", " "))
self.finished.emit(cols, list(rows), cnt, elapsed)
except Exception as e:
_log.error("Query failed SQL: %.300s", self._sql.replace("\n", " "),
exc_info=True)
self.error.emit(str(e))
class SchemaWorker(QThread):
"""Generic async loader for schema introspection calls."""
result = pyqtSignal(object)
error = pyqtSignal(str)
def __init__(self, fn, *args, parent=None):
super().__init__(parent)
self._fn = fn
self._args = args
def run(self):
try:
data = self._fn(*self._args)
self.result.emit(data)
except Exception as e:
_log.error("SchemaWorker error fn=%s args=%s",
getattr(self._fn, "__name__", "?"), self._args,
exc_info=True)
self.error.emit(str(e))
class TableDataWorker(QThread):
"""Load paginated table data in background."""
finished = pyqtSignal(list, list, int) # cols, rows, total_count
error = pyqtSignal(str)
def __init__(self, driver, database, table,
where="", order_by="", limit=1000, offset=0, parent=None):
super().__init__(parent)
self._driver = driver
self._database = database
self._table = table
self._where = where
self._order_by = order_by
self._limit = limit
self._offset = offset
def run(self):
try:
cols, rows, cnt = self._driver.get_table_data(
self._database, self._table,
self._where, self._order_by, self._limit, self._offset
)
total = self._driver.get_table_row_count(
self._database, self._table, self._where
)
self.finished.emit(cols, list(rows), total)
except Exception as e:
_log.error("TableDataWorker error table=%s.%s where=%r",
self._database, self._table, self._where,
exc_info=True)
self.error.emit(str(e))