feat: enrich SQL explorer schema browser with PK/FK, row counts, search, collapsible tables
This commit is contained in:
+54
-6
@@ -2121,24 +2121,72 @@ async def analytics_schema():
|
||||
@app.get("/api/analytics/pg-schema")
|
||||
async def pg_schema():
|
||||
"""Return PostgreSQL table/column metadata for the schema browser."""
|
||||
rows = await pool.fetch("""
|
||||
SELECT t.table_name, c.column_name, c.data_type, c.is_nullable
|
||||
# Columns with ordinal position
|
||||
col_rows = await pool.fetch("""
|
||||
SELECT t.table_name, c.column_name, c.data_type, c.is_nullable,
|
||||
c.column_default
|
||||
FROM information_schema.tables t
|
||||
JOIN information_schema.columns c
|
||||
ON t.table_name = c.table_name AND t.table_schema = c.table_schema
|
||||
WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE'
|
||||
ORDER BY t.table_name, c.ordinal_position
|
||||
""")
|
||||
|
||||
# Primary key columns
|
||||
pk_rows = await pool.fetch("""
|
||||
SELECT kcu.table_name, kcu.column_name
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
AND tc.table_schema = kcu.table_schema
|
||||
WHERE tc.table_schema = 'public' AND tc.constraint_type = 'PRIMARY KEY'
|
||||
""")
|
||||
pk_set: set[tuple[str, str]] = {(r["table_name"], r["column_name"]) for r in pk_rows}
|
||||
|
||||
# Foreign key columns with referenced table
|
||||
fk_rows = await pool.fetch("""
|
||||
SELECT kcu.table_name, kcu.column_name,
|
||||
ccu.table_name AS foreign_table
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
AND tc.table_schema = kcu.table_schema
|
||||
JOIN information_schema.constraint_column_usage ccu
|
||||
ON tc.constraint_name = ccu.constraint_name
|
||||
AND tc.table_schema = ccu.table_schema
|
||||
WHERE tc.table_schema = 'public' AND tc.constraint_type = 'FOREIGN KEY'
|
||||
""")
|
||||
fk_map: dict[tuple[str, str], str] = {
|
||||
(r["table_name"], r["column_name"]): r["foreign_table"] for r in fk_rows
|
||||
}
|
||||
|
||||
# Approximate row counts from pg_stat
|
||||
count_rows = await pool.fetch("""
|
||||
SELECT relname AS table_name, reltuples::bigint AS row_estimate
|
||||
FROM pg_class
|
||||
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')
|
||||
AND relkind = 'r'
|
||||
""")
|
||||
row_counts: dict[str, int] = {r["table_name"]: max(0, r["row_estimate"]) for r in count_rows}
|
||||
|
||||
tables: dict[str, dict[str, Any]] = {}
|
||||
for row in rows:
|
||||
for row in col_rows:
|
||||
tname = row["table_name"]
|
||||
if tname not in tables:
|
||||
tables[tname] = {"name": tname, "columns": []}
|
||||
tables[tname]["columns"].append({
|
||||
tables[tname] = {"name": tname, "row_estimate": row_counts.get(tname, 0), "columns": []}
|
||||
col_info: dict[str, Any] = {
|
||||
"name": row["column_name"],
|
||||
"type": row["data_type"],
|
||||
"nullable": row["is_nullable"] == "YES",
|
||||
})
|
||||
}
|
||||
if (tname, row["column_name"]) in pk_set:
|
||||
col_info["primary_key"] = True
|
||||
fk_ref = fk_map.get((tname, row["column_name"]))
|
||||
if fk_ref:
|
||||
col_info["references"] = fk_ref
|
||||
if row["column_default"] is not None:
|
||||
col_info["has_default"] = True
|
||||
tables[tname]["columns"].append(col_info)
|
||||
return {"catalog": "postgresql", "schema": "public", "tables": list(tables.values())}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user