Initial Codes
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Overview
|
||||
DBClient is a desktop database client built with Python + PyQt6, supporting MySQL, PostgreSQL, SQLite, and MSSQL. Inspired by DBeaver / TablePlus.
|
||||
|
||||
---
|
||||
|
||||
## Development Commands
|
||||
|
||||
**Install dependencies:**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
**Run the application:**
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
There is no test suite or linter config set up.
|
||||
|
||||
**Build distributable (Windows):**
|
||||
```bash
|
||||
pip install pyinstaller
|
||||
python build_app.py # one-folder bundle → dist/DBClient/
|
||||
python build_app.py --onefile # single .exe → dist/DBClient.exe
|
||||
python build_app.py --clean # wipe build/ and dist/ first
|
||||
```
|
||||
The PyInstaller spec is `DBClient.spec`; add new resource files / hidden imports there.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Driver Abstraction (`app/drivers/`)
|
||||
All database operations go through `BaseDriver` (`app/drivers/base.py`). The four concrete drivers (mysql, postgres, sqlite, mssql) each implement the same interface — the UI never imports a specific driver directly. Use the factory `get_driver(db_type, config)` from `app/drivers/__init__.py`. Adding a new DB type means subclassing `BaseDriver` and registering it in the factory.
|
||||
|
||||
Key data types defined in `base.py`: `ColumnInfo`, `IndexInfo`, `ForeignKeyInfo`, `TableInfo`.
|
||||
|
||||
### Async DB Operations (`app/utils/worker.py`)
|
||||
All database I/O runs in background threads. The pattern is:
|
||||
1. Create a `QueryWorker` / `SchemaWorker` / `TableDataWorker` (subclasses of `QRunnable`/`QThread`)
|
||||
2. Connect `signals.result` / `signals.error` to UI slots
|
||||
3. The worker calls the driver and emits results — never call driver methods directly from the GUI thread.
|
||||
|
||||
All worker errors are logged with `exc_info=True` (full traceback) via `app.utils.logger`.
|
||||
|
||||
### Logging (`app/utils/logger.py`)
|
||||
Call `get_logger(__name__)` anywhere to get a module logger. `setup_logging()` is called once in `main.py` and initialises:
|
||||
- `TimedRotatingFileHandler` → `~/.dbclient/logs/dbclient.log` (daily rotation, 7-day retention)
|
||||
- `StreamHandler` to stderr (WARNING+ only, for dev)
|
||||
- `sys.excepthook` and `threading.excepthook` to capture uncaught exceptions with full tracebacks
|
||||
- `qInstallMessageHandler` to capture Qt internal warnings
|
||||
|
||||
View logs inside the app via **Help → View App Logs (Ctrl+L)**.
|
||||
|
||||
### Signal/Slot Flow
|
||||
`SchemaBrowser` (left sidebar) emits signals when the user double-clicks a table or selects a database. `MainWindow` connects these to open workspace tabs (`TableViewer`, `TableStructure`, `SQLEditor`). New UI interactions should follow this pattern: sidebar emits, main window routes, tabs receive.
|
||||
|
||||
### Data Persistence
|
||||
All user data lives under `~/.dbclient/`:
|
||||
- `connections.json` — connection profiles (passwords omitted; stored in OS keychain via `keyring`)
|
||||
- `settings.json` — app-wide preferences (theme, font size, page size, timeouts)
|
||||
- `history.db` — SQLite store for query history
|
||||
|
||||
`app/config/connections.py` handles profile CRUD + keyring integration. `app/config/settings.py` is a settings singleton.
|
||||
|
||||
### UI Structure
|
||||
`MainWindow` (`app/main_window.py`) owns a `QSplitter` with `SchemaBrowser` on the left and a `QTabWidget` workspace on the right. Workspace tabs are created dynamically: `SQLEditor` for query tabs, `TableViewer` for data browsing, `TableStructure` for DDL inspection.
|
||||
|
||||
The `ResultTableModel` (`app/models/result_table_model.py`) is a `QAbstractTableModel` — query results should always go through it rather than populating `QTableWidget` directly.
|
||||
|
||||
### Styling
|
||||
`resources/style.qss` is a Catppuccin Mocha dark theme applied globally at startup in `main.py`. Widget-specific overrides belong here, not as inline `setStyleSheet()` calls.
|
||||
|
||||
---
|
||||
|
||||
## Known Quirks
|
||||
|
||||
### TableViewer selection signals
|
||||
`QItemSelectionModel.selectionChanged` becomes unreliable after `beginResetModel/endResetModel` cycles (triggered on every data load). Edit/Delete button enabling is driven by `QTableView.clicked` (primary, mouse) and `selectionChanged` (secondary, keyboard). Do not remove the `clicked` connection — removing it re-breaks the buttons.
|
||||
|
||||
### NULL-aware WHERE clauses
|
||||
All four drivers have a `_where(where: dict) → (clause_str, params)` static helper that emits `col IS NULL` for `None` values instead of `col = NULL`. All `update_row` and `delete_row` calls go through this helper. Do not bypass it.
|
||||
|
||||
### Password hashing in RowDialog
|
||||
`RowDialog` detects password-like column names (via `_is_password_col()`) and hashes plain-text input with bcrypt before storing. In edit mode, leaving a password field empty omits that column from the UPDATE so the existing hash is preserved.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Status
|
||||
|
||||
### Complete
|
||||
- Connection manager (add/edit/delete, test, color coding, keyring storage)
|
||||
- Schema browser (live tree: connections → databases → tables/views/functions/procedures/triggers, search, context menus, delete connection from active node)
|
||||
- SQL editor (multi-tab, syntax highlighting, line numbers, Ctrl+/ comment toggle, F5/Ctrl+Enter execute)
|
||||
- Results panel (sortable `QAbstractTableModel`, export CSV/JSON/SQL INSERT, pagination, execution time)
|
||||
- Table viewer (paginated grid 50/100/All, add/edit/delete rows via dialog, WHERE filter, bcrypt password hashing)
|
||||
- Table structure view (columns, indexes, FKs, DDL with syntax highlighting, add/drop/rename column designer)
|
||||
- Query history (auto-log with timestamp/duration/status, search, replay, persisted in `history.db`)
|
||||
- All 4 DB drivers (MySQL, PostgreSQL, SQLite, MSSQL)
|
||||
- Process list viewer (`app/ui/process_list.py`) with 5 s auto-refresh and kill query
|
||||
- Import CSV/JSON dialog (`app/ui/import_dialog.py`) with preview and progress bar
|
||||
- Database dump export (`app/ui/dump_dialog.py`): schema/data/both, table selector, progress bar
|
||||
- Tools menu in MainWindow (Process List, Import CSV/JSON, Export Database Dump, User Management)
|
||||
- PyInstaller packaging (`DBClient.spec` + `build_app.py`)
|
||||
- User & privilege management (`app/ui/user_manager.py`): list/create/drop users, GRANT/REVOKE per-DB (MySQL + PostgreSQL)
|
||||
- EXPLAIN plan diagram (`app/ui/explain_view.py`): visual node tree + raw table; opened from SQL editor "🔎 Explain" button
|
||||
- Application logging (`app/utils/logger.py` + `app/ui/log_viewer.py`): rotating file logs, unhandled exception hooks, in-app log viewer (Help → View App Logs)
|
||||
|
||||
### Not Yet Implemented
|
||||
- (All planned features are now complete)
|
||||
Reference in New Issue
Block a user