461bb77298
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>
131 lines
4.9 KiB
Markdown
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.
|