Agrega diagrama de relaciones (FK) al Query Runner

- GetSchemaRelations: trae todas las llaves foráneas de la base con
  consulta específica por motor (Postgres/MySQL/MSSQL/SQLite). No
  aplica a Redis/Mongo (schemaless).
- Endpoint GET /query-runner/relations, con el mismo chequeo de
  autorización por conexión que ya usa RunQuery — de paso se lo
  agrego también a GetDatabases/GetTables, que no lo tenían.
- UI: botón "Ver relaciones" (diagrama completo) y un ícono por tabla
  en el árbol lateral (relaciones solo de esa tabla), renderizado con
  Mermaid.js servido localmente (public/js/mermaid.min.js, sin CDN).
This commit is contained in:
Lizandro GD
2026-08-08 23:11:48 +00:00
parent b7fba43ea1
commit 21d8cd5260
6 changed files with 3888 additions and 0 deletions
@@ -76,6 +76,9 @@ func GetDatabases(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
if !usuarioPuedeUsarConx(c, conx.ID) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "No tienes acceso a esta conexión"})
}
dbs, err := services.ListDatabases(conx)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
@@ -90,6 +93,9 @@ func GetTables(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
if !usuarioPuedeUsarConx(c, conx.ID) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "No tienes acceso a esta conexión"})
}
dbName := c.Query("db", "")
tables, err := services.ListTables(conx, dbName)
if err != nil {
@@ -98,6 +104,25 @@ func GetTables(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"data": tables})
}
// GetRelations lista las llaves foráneas de toda una base de datos, para
// poder dibujar el diagrama de relaciones entre tablas.
// GET /app/query-runner/relations?conx_db_id=1&db=mydb
func GetRelations(c *fiber.Ctx) error {
conx, err := loadConxDb(c.Query("conx_db_id", "0"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
if !usuarioPuedeUsarConx(c, conx.ID) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "No tienes acceso a esta conexión"})
}
dbName := c.Query("db", "")
relaciones, err := services.GetSchemaRelations(conx, dbName)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": relaciones})
}
// usuarioPuedeUsarConx verifica que el usuario autenticado pueda ejecutar SQL
// contra esa conexión: admin ve todas, el resto solo las que su rol tiene
// asignadas en Role.ConxDBs (el mismo criterio que ya usa GetConxDbList para