feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
---
|
||||
id: build_join_graph_py_datascience
|
||||
name: build_join_graph
|
||||
kind: function
|
||||
lang: py
|
||||
domain: datascience
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "def build_join_graph(fk_candidates: list, tables: list = None) -> dict"
|
||||
description: "Construye un grafo de relaciones inter-tabla a partir de FK candidatas (salida fk_candidates de infer_fk_containment_duckdb): nodos con grados y rol (fact/dimension/bridge/standalone), aristas por FK, hubs (candidatas a tabla de hechos) y un diagrama Mermaid graph LR pegable. Funcion pura, sin deps externas, no muta el input."
|
||||
tags: [eda, relations, join, schema, graph, mermaid, star-schema, datascience]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
example: |
|
||||
from datascience import build_join_graph
|
||||
fks = [
|
||||
{"from_table": "orders", "from_col": "customer_id",
|
||||
"to_table": "customers", "to_col": "id",
|
||||
"inclusion": 1.0, "cardinality": "many-to-one"},
|
||||
{"from_table": "orders", "from_col": "product_id",
|
||||
"to_table": "products", "to_col": "id",
|
||||
"inclusion": 0.98, "cardinality": "many-to-one"},
|
||||
]
|
||||
g = build_join_graph(fks)
|
||||
# g["hubs"] == ["orders"]; orders -> role "fact", customers/products -> "dimension"
|
||||
print(g["mermaid"])
|
||||
tested: true
|
||||
tests:
|
||||
- "test_star_schema_roles_and_hub"
|
||||
- "test_two_edges_built"
|
||||
- "test_mermaid_contains_tables_and_arrows"
|
||||
- "test_bridge_role"
|
||||
- "test_standalone_node_from_tables_list"
|
||||
- "test_empty_list_does_not_crash"
|
||||
- "test_none_input_does_not_crash"
|
||||
- "test_malformed_entries_skipped"
|
||||
- "test_does_not_mutate_input"
|
||||
test_file_path: "python/functions/datascience/build_join_graph_test.py"
|
||||
file_path: "python/functions/datascience/build_join_graph.py"
|
||||
params:
|
||||
- name: fk_candidates
|
||||
desc: >
|
||||
lista de dicts, cada uno una FK candidata con al menos las claves
|
||||
from_table, from_col, to_table, to_col, inclusion, cardinality. Suele ser
|
||||
la salida `fk_candidates` de infer_fk_containment_duckdb. Las claves se
|
||||
leen de forma defensiva con .get(...); entradas que no son dict o que no
|
||||
tienen from_table/to_table se ignoran sin fallar. None se trata como [].
|
||||
- name: tables
|
||||
desc: >
|
||||
lista opcional de nombres de TODAS las tablas. Sirve para incluir como
|
||||
nodos aislados (role "standalone") las tablas que no aparecen en ninguna
|
||||
FK. Si es None, los nodos se derivan solo de las aristas.
|
||||
output: >
|
||||
dict con nodes (list[dict] con table, out_degree, in_degree, role donde role
|
||||
es "fact"|"dimension"|"bridge"|"standalone"), edges (list[dict] con
|
||||
from_table, from_col, to_table, to_col, inclusion, cardinality, una por FK
|
||||
valida), mermaid (str con un diagrama `graph LR` pegable en un bloque
|
||||
```mermaid, una arista por FK etiquetada `from_col->to_col`) y hubs (list[str]
|
||||
de tablas con out_degree>0 ordenadas por out_degree descendente, candidatas a
|
||||
tabla de hechos / star schema).
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
from datascience import build_join_graph
|
||||
|
||||
# fk_candidates concreto: orders apunta a customers y a products (estrella).
|
||||
fks = [
|
||||
{"from_table": "orders", "from_col": "customer_id",
|
||||
"to_table": "customers", "to_col": "id",
|
||||
"inclusion": 1.0, "cardinality": "many-to-one"},
|
||||
{"from_table": "orders", "from_col": "product_id",
|
||||
"to_table": "products", "to_col": "id",
|
||||
"inclusion": 0.98, "cardinality": "many-to-one"},
|
||||
]
|
||||
|
||||
g = build_join_graph(fks)
|
||||
|
||||
g["hubs"] # ["orders"]
|
||||
# nodes: orders -> role "fact" (out_degree 2, in_degree 0),
|
||||
# customers/products -> role "dimension" (in_degree 1, out_degree 0)
|
||||
print(g["mermaid"])
|
||||
```
|
||||
|
||||
El campo `mermaid` se pega tal cual en un bloque ```mermaid:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
orders["orders"] -->|customer_id->id| customers["customers"]
|
||||
orders["orders"] -->|product_id->id| products["products"]
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando hayas inferido las foreign keys de una base de datos con
|
||||
`infer_fk_containment_duckdb` (grupo `eda`) y necesites **visualizar el esquema
|
||||
relacional**: ver de un vistazo que tabla es la de hechos (hub/star schema),
|
||||
cuales son dimensiones y cuales quedan sueltas. Devuelve un diagrama Mermaid
|
||||
pegable en docs, un report o un dashboard, mas el grafo en dict para razonar
|
||||
sobre los grados (priorizar joins, detectar tablas puente, planear el modelo
|
||||
dimensional). Es la capa de grafo sobre las FK crudas: lee las candidatas, no
|
||||
toca la base de datos.
|
||||
|
||||
## Notas
|
||||
|
||||
Funcion pura, sin I/O ni dependencias externas (solo stdlib), no muta
|
||||
`fk_candidates`. Tolera lista vacia o `None` (devuelve grafo vacio con un
|
||||
mermaid minimo `graph LR` con nota `empty`) y entradas malformadas (no-dict o
|
||||
sin from_table/to_table se ignoran).
|
||||
|
||||
Heuristica de `role` por nodo, basada solo en grados:
|
||||
|
||||
- **fact** — `out_degree > 0` y `in_degree == 0`: apunta a otras tablas y nadie
|
||||
le apunta. Es la candidata a tabla de hechos.
|
||||
- **dimension** — `in_degree > 0` y `out_degree == 0`: solo recibe referencias
|
||||
(tabla maestra / catalogo).
|
||||
- **bridge** — `out_degree > 0` e `in_degree > 0`: apunta y recibe (tabla puente
|
||||
o asociativa de una relacion many-to-many).
|
||||
- **standalone** — sin aristas (solo aparece si se paso en `tables`).
|
||||
|
||||
`hubs` ordena por `out_degree` descendente las tablas con `out_degree > 0`. Para
|
||||
un star schema limpio, `hubs[0]` es la tabla de hechos. Los IDs de nodo en el
|
||||
Mermaid se sanean (no-alfanumerico -> `_`) pero la etiqueta visible conserva el
|
||||
nombre original de la tabla.
|
||||
```
|
||||
Reference in New Issue
Block a user