Files
fn_registry/dev/issues/0032-cpp-sql-workbench.md
T
egutierrez a11a58dab0 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

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_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

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.
  • 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

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.