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>
4.9 KiB
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_editoresta 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
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 seanSELECT/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 asqlite_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_editorconCodeLang::SQLsi disponible (compile-time#ifdef FN_HAS_TEXT_EDITORo detectar via include guard). - 3.5 Resultado: usar
table_view_cpp_vizcon 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.cppcondemo_sql_workbench(): abreregistry.db(path resuelto via env varFN_REGISTRY_ROOTo cwd), modo readonly. La sidebar muestrafunctions,types, etc. - 5.2 Registrar.
Fase 6 — Tests + docs
- 6.1 Test
sql_workbench_run_querycon 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
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.dbabierto la pasa). - Rows como strings: SQLite ya las da convertibles. La
table_viewespera 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 viaprocess_runner_cpp_corepatrón). - Memoria con resultados grandes: cap a 10000 filas. Documentar.