Files
2026-05-11 16:28:44 +02:00

130 lines
3.7 KiB
C++

// 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 <imgui.h>
#include <sqlite3.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
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