Files
graph_explorer/issues/completed/0010-table-node.md
T
egutierrez 082008bc00 feat(table-node): DuckDB foundation + render colapsado (issue 0010)
- tableview.{h,cpp}: capa C sobre DuckDB v1.1.3.
  * tableview_smoke_test (SELECT 42).
  * tableview_count (con sql_filter opcional).
  * tableview_page (LEFT JOIN sobre ops.entities via ATTACH para flag promoted).
  * tableview_create (inserta entidad type_ref='Table' con metadata pointer).
  * tableview_refresh_counts (lee Table entities, count cada DuckDB y cachea
    por user_data hash).
  * tableview_resolve_path (rel a dirname(ops_db) o absoluto).
- AppState::table_node_counts cache, refrescado tras load_input y mutaciones.
- views_table_overlay: rectangulo redondeado overlay ("Table  N") encima
  de cada nodo type_ref='Table'. Sigue camara via cam_x/cam_y/zoom.
- main.cpp:
  * --test-duckdb <path> smoke (SELECT 42).
  * --test-tableview <path> bulk test (1M rows count + page offset).
  * Refresh de counts tras load + reload_after_mutation.
  * Llamada a views_table_overlay despues de graph_labels_draw.
- CMakeLists.txt: link DuckDB::DuckDB + duckdb_copy_runtime.

Smoke tests:
- 1M rows count + page(offset=500k, limit=10) en 0.65 s end-to-end.
- Operations.db con un nodo Table apuntando a duckdb 1M filas: refresh
  reporta correctamente "1 tables, 1000000 total rows".
2026-05-01 01:24:43 +02:00

96 lines
3.3 KiB
Markdown

---
id: 0010
title: Nodo tabla — DuckDB foundation + render colapsado
status: completed
priority: high
created: 2026-04-30
revised: 2026-05-01
completed: 2026-05-01
depends_on: [0004, 0005, 0008]
---
## Objetivo
Tier de almacenamiento tabular para nodos `Table` que pueden contener millones
de filas sin saturar `operations.db` ni el grafo. Las "filas" viven en un
`.duckdb` por proyecto (o por tabla) y se promueven a entidades reales del
grafo solo cuando se necesita interactuar con ellas individualmente
(relaciones, edicion, etc.).
Esta issue cubre **fase 1** — vendoring de DuckDB, funciones `tableview_*`
core, y render colapsado del nodo Table en el viewport. La fase 2 (UI
expandida, paginacion, promote/demote, ingesta CSV/Parquet) va en issue
0011.
## Modelo de datos
**Dos tiers** por proyecto:
```
projects/<proj>/apps/graph_explorer/
operations.db # SQLite — grafo (entities + relations + filas promovidas)
tables/
<slug>.duckdb # DuckDB — bulk tabular (millones de filas)
```
El nodo Table es una entidad normal con `type_ref = 'Table'` y metadata que
apunta a su dataset DuckDB. **No contiene filas internamente** — es una vista.
```json
{
"duckdb_path": "tables/sospechosos.duckdb",
"table_name": "people",
"row_type": "Person",
"id_column": "id",
"label_column": "name",
"columns": ["name","age","email"],
"filter_sql": "",
"expanded": false
}
```
Una fila promovida es una entidad en `operations.db` con metadata de origen:
```json
{
"source": {
"duckdb": "tables/sospechosos.duckdb",
"table": "people",
"row_id": "p_42"
},
"name": "Ana Lopez",
"age": 33
}
```
## Cambios en codigo
- **Vendor DuckDB** en `cpp/vendor/duckdb/` (amalgamation o precompiled). Add
library en `cpp/CMakeLists.txt`.
- Nuevo paquete `cpp/functions/duck/`:
- `duck_open(path) -> duckdb_database` (con `duckdb_open` + `duckdb_connect`).
- `duck_query(conn, sql, params) -> result` wrapper.
- `entity_ops` (o `tableview.{h,cpp}` en la app) — funciones a nivel de app:
- `tableview_create(ops_db, duckdb_path, duck_table, row_type, char* out_id)`
crea entidad `Table` con metadata + commit en `operations.db`.
- `tableview_count(duckdb_path, sql_filter, int64_t* out)`.
- `tableview_page(duckdb_path, sql_filter, offset, limit, vector<TablePageRow>* out)`.
- `TablePageRow` lleva los campos del `columns[]` resueltos a string +
`promoted` (LEFT JOIN contra `ops.entities`).
- `graph_load_from_operations`: filtrar relaciones `CONTAINS_ROW` (heredado
del modelo viejo, ya no se emiten pero por si se topa con dbs antiguas).
- `views.cpp`:
- Detectar nodos `type_ref == "Table"` al renderizar etiquetas/contadores.
- Overlay con `ImGui::GetForegroundDrawList()` por cada nodo Table:
rectangulo redondeado + label "Table · N filas".
## Definicion de hecho
- DuckDB compila y linka en linux + windows (cmake target).
- Smoke test: abrir un `.duckdb` vacio, crear tabla con 1M filas (CTAS desde
`range`), correr `SELECT COUNT(*)` < 100 ms.
- `tableview_create` + `tableview_count` + `tableview_page` con tests.
- Un nodo `type_ref='Table'` en el grafo se renderiza con un cuadrado overlay
encima del circulo GPU, con contador de filas obtenido por `tableview_count`.
- El contador refresca al recargar el grafo o tras un INSERT en su DuckDB.