homelab_automation/app/scripts/generate_db_docs.py
Bruno Charest 984d06a223
Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
feat: Implement comprehensive database schema with new models, CRUD operations, and documentation for host metrics, Docker management, and terminal sessions, while removing old test files.
2026-03-05 10:16:13 -05:00

115 lines
4.3 KiB
Python

import os
import sys
# Ensure the parent directory is in the python path to load app.models
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
if parent_dir not in sys.path:
sys.path.insert(0, parent_dir)
from app.models import Base
from sqlalchemy import MetaData
metadata: MetaData = Base.metadata
def get_mermaid_type(column_type):
"""Clean the column type for mermaid ERD compatibility"""
t = str(column_type).upper().split('(')[0]
return t.replace(' ', '_')
def generate_mermaid_erd(metadata: MetaData):
lines = ["erDiagram"]
# Render tables and columns
for table_name, table in sorted(metadata.tables.items()):
lines.append(f" {table_name} {{")
for column in table.columns:
col_type = get_mermaid_type(column.type)
constraints = []
if column.primary_key:
constraints.append("PK")
if column.foreign_keys:
constraints.append("FK")
# Additional constraint notes
notes = '"nullable"' if column.nullable else ""
constraints_str = " ".join(constraints)
if notes:
constraints_str += f" {notes}"
lines.append(f" {col_type} {column.name} {constraints_str}")
lines.append(" }")
# Render relationships
for table_name, table in sorted(metadata.tables.items()):
for column in table.columns:
for fk in column.foreign_keys:
target_table = fk.column.table.name
# Usually a 1-to-many from target to source in a relational schema
lines.append(f" {target_table} ||--o{{ {table_name} : \"{column.name}\"")
return "\n".join(lines)
def generate_markdown_docs(metadata: MetaData):
lines = ["# Documentation du Modèle de Données (Base de Données)\n"]
lines.append("Cette documentation a été générée automatiquement à partir des modèles SQLAlchemy.\n")
lines.append("## 1. Diagramme Entité-Association (ERD)\n")
lines.append("Le schéma ci-dessous montre l'architecture des tables et leurs relations :\n")
lines.append("```mermaid")
lines.append(generate_mermaid_erd(metadata))
lines.append("```\n")
lines.append("## 2. Dictionnaire de Données (Tables)\n")
for table_name, table in sorted(metadata.tables.items()):
lines.append(f"### Table : `{table_name}`")
if table.comment:
lines.append(f"> {table.comment}\n")
else:
lines.append("\n")
lines.append("| Colonne | Type | Clé Primaire | Clé Étrangère | Nullable | Défaut |")
lines.append("|---------|------|--------------|---------------|----------|--------|")
for column in table.columns:
col_type = str(column.type)
pk = "✅ Oui" if column.primary_key else "-"
fk_list = list(column.foreign_keys)
if fk_list:
fk_target = fk_list[0].column.table.name + "." + fk_list[0].column.name
fk = f"🔗 `{fk_target}`"
else:
fk = "-"
nullable = "Oui" if column.nullable else "**Non**"
# Format default value safely
default_val = "-"
if column.default:
if column.default.is_scalar:
default_val = f"`{column.default.arg}`"
elif column.default.is_callable:
default_val = "*(auto generate)*"
elif column.server_default:
default_val = f"`{column.server_default.arg}`"
lines.append(f"| `{column.name}` | `{col_type}` | {pk} | {fk} | {nullable} | {default_val} |")
lines.append("\n")
return "\n".join(lines)
if __name__ == "__main__":
docs_content = generate_markdown_docs(metadata)
docs_dir = os.path.join(parent_dir, 'docs')
os.makedirs(docs_dir, exist_ok=True)
output_path = os.path.join(docs_dir, 'database_schema.md')
with open(output_path, "w", encoding="utf-8") as f:
f.write(docs_content)
print(f"La documentation a été générée avec succès : {output_path}")