// Demo de sql_workbench (Core, issue 0032). // // Abre `registry.db` en modo readonly y deja que el componente liste sus // tablas en la sidebar. La idea es probar el ciclo Run + tabla + historial // contra una DB real sin riesgo de mutarla. #include "demos.h" #include "demo.h" #include "core/sql_workbench.h" #include "core/tokens.h" #include #include #include #include #include #include namespace gallery { namespace { struct SqlDemoState { sqlite3* db = nullptr; fn::SqlWorkbenchState wb; bool tried_open = false; std::string db_path; std::string open_error; }; SqlDemoState& state() { static SqlDemoState s; return s; } // Resuelve la ruta a registry.db: env FN_REGISTRY_ROOT/registry.db si existe, // si no, prueba ./registry.db, ../registry.db, ../../registry.db (build tree). std::string resolve_registry_db() { if (const char* env = std::getenv("FN_REGISTRY_ROOT")) { std::string p = std::string(env) + "/registry.db"; if (FILE* f = std::fopen(p.c_str(), "rb")) { std::fclose(f); return p; } } const char* candidates[] = { "registry.db", "../registry.db", "../../registry.db", "../../../registry.db", "../../../../registry.db", }; for (const char* c : candidates) { if (FILE* f = std::fopen(c, "rb")) { std::fclose(f); return c; } } return ""; } void ensure_open() { auto& s = state(); if (s.tried_open) return; s.tried_open = true; s.db_path = resolve_registry_db(); if (s.db_path.empty()) { s.open_error = "registry.db not found (tried FN_REGISTRY_ROOT and parent dirs)"; return; } int rc = sqlite3_open_v2(s.db_path.c_str(), &s.db, SQLITE_OPEN_READONLY, nullptr); if (rc != SQLITE_OK) { s.open_error = sqlite3_errmsg(s.db); if (s.db) { sqlite3_close(s.db); s.db = nullptr; } return; } s.wb.readonly = true; // Query inicial mas util para el demo: lista de funciones del registry. s.wb.query = "SELECT id, kind, purity, domain\n" "FROM functions\n" "ORDER BY id\n" "LIMIT 50;"; } } // namespace void demo_sql_workbench() { using namespace fn_tokens; demo_header("sql_workbench", "v1.0.0", "Workbench SQL: editor con highlighting, schema sidebar, tabla de " "resultados e historial. Ejecuta queries contra una sqlite3* del caller. " "En este demo, registry.db abierto en modo readonly."); ensure_open(); auto& s = state(); if (!s.open_error.empty()) { ImGui::PushStyleColor(ImGuiCol_Text, colors::error); ImGui::TextWrapped("could not open registry.db: %s", s.open_error.c_str()); ImGui::PopStyleColor(); ImGui::PushStyleColor(ImGuiCol_Text, colors::text_muted); ImGui::TextWrapped("Set FN_REGISTRY_ROOT to the repo root or run from the repo cwd."); ImGui::PopStyleColor(); return; } ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); ImGui::Text("db: %s (readonly)", s.db_path.c_str()); ImGui::PopStyleColor(); section("workbench"); { ImVec2 avail = ImGui::GetContentRegionAvail(); // Reserva un pelin para el code_block de abajo. float h = avail.y - 110.0f; if (h < 320.0f) h = 320.0f; fn::sql_workbench("##gallery_sql", s.db, s.wb, ImVec2(-1, h)); } code_block( "sqlite3* db = nullptr;\n" "sqlite3_open_v2(\"registry.db\", &db, SQLITE_OPEN_READONLY, nullptr);\n" "fn::SqlWorkbenchState st;\n" "st.readonly = true;\n" "fn::sql_workbench(\"##sql\", db, st, ImVec2(-1, -1));" ); } } // namespace gallery