Files
graph_explorer/issues/0010-table-node.md
T
egutierrez 20d8bbf360 docs(issues): rewrite 0010 con DuckDB + new 0011 (UI fase 2)
0010 cambia de modelo SQLite CONTAINS_ROW a tier DuckDB:
operations.db sigue con grafo + filas promovidas, tablas grandes
viven en projects/<proj>/apps/graph_explorer/tables/<slug>.duckdb.
0011 separa la fase 2 (UI expandida + promote/demote + ingesta CSV).
2026-05-01 01:14:52 +02:00

95 lines
3.3 KiB
Markdown

---
id: 0010
title: Nodo tabla — DuckDB foundation + render colapsado
status: pending
priority: high
created: 2026-04-30
revised: 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.