Files
fn_registry/dev/issues/0032-cpp-sql-workbench.md
T
egutierrez 461bb77298 docs(issues): añadir 0025-0036 — features C++ para registry y primitives_gallery
12 issues nuevos para implementacion paralela: text_editor, file_watcher,
gl_texture_load, gl_compute+pingpong+DAG Compute, ImPlot3D, mesh_viewer,
audio reactivo, animation curves, sql_workbench, http+ws inspector,
scientific viz (5 charts), map_tiles, image_canvas + webcam_texture.

Cada issue añade funciones al registry y un demo propio en
primitives_gallery/demos_<feature>.cpp para minimizar conflictos en paralelo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:48:18 +02:00

131 lines
4.9 KiB
Markdown

# 0032 — C++ sql_workbench
## APP Metadata
| Campo | Valor |
|-------|-------|
| **ID** | 0032 |
| **Estado** | pendiente |
| **Prioridad** | media |
| **Tipo** | feature — C++ core (cpp/functions/core) |
## Dependencias
`text_editor_cpp_core` (issue 0025) — recomendado pero no bloqueante: si no esta listo, fallback a `ImGui::InputTextMultiline`. `table_view_cpp_viz`, `tokens_cpp_core`. SQLite ya esta en uso por `layout_storage_sqlite`.
**Desbloquea:** explorar `registry.db` y `operations.db` desde una app C++ sin salir al CLI; debugging visual de assertions/executions.
---
## Objetivo
Componente ImGui que combina:
- Editor SQL (con highlight si `text_editor` esta disponible).
- Botón "Run" que ejecuta sobre una `sqlite3*` proporcionada por el caller.
- Tabla de resultados (`table_view`) con sorting y scrolling.
- Lista de tablas/views del schema (sidebar) clickable que insertan `SELECT * FROM <name> LIMIT 100;`.
- Historial de queries en memoria + boton "Save" a un archivo `.sql.history`.
Demo en `primitives_gallery` apuntando a `registry.db` (read-only).
## Contexto
Manualmente uso `sqlite3` CLI o DBeaver para inspeccionar `registry.db` mientras desarrollo. Tener un workbench in-app abre la posibilidad de apps C++ que sean dashboards-cum-SQL-explorers contra `operations.db` (entities, executions, assertions).
## Arquitectura
```
cpp/functions/core/
├── sql_workbench.h # NEW
├── sql_workbench.cpp # NEW
└── sql_workbench.md # NEW
cpp/apps/primitives_gallery/
├── demos_sql.cpp # NEW
├── demos.h # MOD
├── main.cpp # MOD
└── CMakeLists.txt # MOD
```
### Pure core / impure shell
`sql_workbench_cpp_core`: `kind: component`, `purity: impure` (ejecuta SQL contra una DB).
### API propuesta
```cpp
namespace fn {
struct SqlWorkbenchState {
std::string query = "SELECT name FROM sqlite_master WHERE type='table';";
std::string last_error;
std::vector<std::string> columns;
std::vector<std::vector<std::string>> rows;
std::vector<std::string> history; // queries ejecutadas
bool readonly = false;
};
// db: caller-owned sqlite3*. NO se cierra desde el componente.
void sql_workbench(const char* id, sqlite3* db, SqlWorkbenchState& state, ImVec2 size = {-1, -1});
}
```
## Tareas
### Fase 1 — Backend de ejecucion
- 1.1 Implementar `sql_workbench_run_query(sqlite3*, const char* sql, SqlWorkbenchState&)`: prepara, step, lee columnas y filas como strings. Limpia errores anteriores.
- 1.2 Si `state.readonly=true`, rechazar comandos que no sean `SELECT`/`PRAGMA`/`EXPLAIN`.
- 1.3 Cap rows a 10000 para no congelar UI; mostrar warning si se trunca.
### Fase 2 — Schema sidebar
- 2.1 `sql_workbench_list_schema(sqlite3*) -> {tables: [], views: [], indices: []}`. Query a `sqlite_master`.
- 2.2 Sidebar collapsable con tablas. Click → insertar `SELECT * FROM <t> LIMIT 100;` en el editor.
### Fase 3 — UI
- 3.1 Layout: panel izquierdo schema (200px), panel derecho dividido vertical (editor arriba, tabla resultado abajo).
- 3.2 Boton Run + atajo Ctrl+Enter.
- 3.3 Barra inferior: status (`5 rows in 12.3 ms`), error en rojo si hubo.
- 3.4 Editor: usar `text_editor` con `CodeLang::SQL` si disponible (compile-time `#ifdef FN_HAS_TEXT_EDITOR` o detectar via include guard).
- 3.5 Resultado: usar `table_view_cpp_viz` con sorting por columnas.
### Fase 4 — Historial
- 4.1 Cada Run exitoso aparea la query a `state.history`.
- 4.2 Popup "History" con las ultimas 50; click → recargar al editor.
### Fase 5 — Gallery demo
- 5.1 `demos_sql.cpp` con `demo_sql_workbench()`: abre `registry.db` (path resuelto via env var `FN_REGISTRY_ROOT` o cwd), modo readonly. La sidebar muestra `functions`, `types`, etc.
- 5.2 Registrar.
### Fase 6 — Tests + docs
- 6.1 Test `sql_workbench_run_query` con DB en memoria: crea tabla, insert, select, verifica columns/rows.
- 6.2 Test rechazo de DML en modo readonly.
- 6.3 `./fn index` + `./fn show sql_workbench_cpp_core`.
## Ejemplo de uso
```cpp
sqlite3* db; sqlite3_open_v2("registry.db", &db, SQLITE_OPEN_READONLY, nullptr);
fn::SqlWorkbenchState st; st.readonly = true;
fn::run_app("sql", [&]{
fn::sql_workbench("##sql", db, st);
});
sqlite3_close(db);
```
## Decisiones de diseño
- **Caller-owned DB**: el workbench no abre/cierra. Permite reusar conexiones del host (un app que ya tiene `operations.db` abierto la pasa).
- **Rows como strings**: SQLite ya las da convertibles. La `table_view` espera strings, sin conversion extra.
- **Readonly opt-in**: por defecto permite escribir; el caller decide.
## Riesgos
- **Queries que cuelgan UI**: documentar; en MVP, ejecucion sincrona en main thread. Si bloquea, considerar `std::thread` (ya disponible via `process_runner_cpp_core` patrón).
- **Memoria con resultados grandes**: cap a 10000 filas. Documentar.