refaktorálás javításai
This commit is contained in:
133
backend/app/scripts/unified_db_audit.py
Normal file
133
backend/app/scripts/unified_db_audit.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from sqlalchemy import inspect, text
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from sqlalchemy.dialects.postgresql import JSONB, ENUM, NUMERIC
|
||||
|
||||
# Elérési utak beállítása
|
||||
BASE_DIR = Path(__file__).resolve().parents[2]
|
||||
sys.path.append(str(BASE_DIR))
|
||||
|
||||
try:
|
||||
from app.database import Base, engine
|
||||
from app.core.config import settings
|
||||
except ImportError as e:
|
||||
print(f"❌ Hiba az alapvető importoknál: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def dynamic_import_models(models_dir: Path):
|
||||
"""
|
||||
Automatikusan bejárja az app/models mappát és beimportál minden .py fájlt,
|
||||
hogy a Base.metadata.tables feltöltődjön.
|
||||
"""
|
||||
print(f"🔍 Modellek dinamikus felderítése itt: {models_dir}...")
|
||||
count = 0
|
||||
for root, _, files in os.walk(models_dir):
|
||||
for file in files:
|
||||
if file.endswith(".py") and file != "__init__.py":
|
||||
full_path = Path(root) / file
|
||||
# Modul név képzése (pl. app.models.identity.user)
|
||||
rel_path = full_path.relative_to(BASE_DIR)
|
||||
module_name = str(rel_path).replace(os.sep, ".").replace(".py", "")
|
||||
|
||||
try:
|
||||
spec = importlib.util.spec_from_file_location(module_name, full_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
count += 1
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Nem sikerült importálni: {module_name} -> {e}")
|
||||
print(f"✅ {count} modell fájl sikeresen betöltve a memóriába.\n")
|
||||
|
||||
async def run_unified_audit():
|
||||
# 1. Modellek betöltése
|
||||
models_path = BASE_DIR / "app" / "models"
|
||||
dynamic_import_models(models_path)
|
||||
|
||||
print(f"🔗 Kapcsolódás az adatbázishoz: {settings.POSTGRES_DB}")
|
||||
|
||||
async with engine.connect() as conn:
|
||||
inspector = await conn.run_sync(inspect)
|
||||
all_db_schemas = await conn.run_sync(lambda c: inspector.get_schema_names())
|
||||
|
||||
# Kigyűjtjük a modellekben definiált sémákat
|
||||
expected_schemas = sorted({t.schema for t in Base.metadata.sorted_tables if t.schema})
|
||||
|
||||
mismatches = 0
|
||||
suggestions = []
|
||||
|
||||
for sc in expected_schemas:
|
||||
print(f"\n--- 🛰️ DOMAIN AUDIT: '{sc}' ---")
|
||||
if sc not in all_db_schemas:
|
||||
print(f"❌ KRITIKUS: A(z) '{sc}' séma hiányzik!")
|
||||
mismatches += 1
|
||||
continue
|
||||
|
||||
db_tables = await conn.run_sync(lambda c: inspector.get_table_names(schema=sc))
|
||||
model_tables = [t for t in Base.metadata.sorted_tables if t.schema == sc]
|
||||
|
||||
for table in model_tables:
|
||||
t_name = table.name
|
||||
if t_name not in db_tables:
|
||||
print(f"❌ HIÁNYZÓ TÁBLA: {sc}.{t_name}")
|
||||
mismatches += 1
|
||||
suggestions.append(f"-- Hozd létre a táblát: {sc}.{t_name}")
|
||||
continue
|
||||
|
||||
# Oszlopok lekérése a DB-ből
|
||||
db_cols = {c['name']: c for c in await conn.run_sync(
|
||||
lambda c: inspector.get_columns(t_name, schema=sc)
|
||||
)}
|
||||
|
||||
# Oszlopok lekérése a Modellből
|
||||
for col in table.columns:
|
||||
if col.name not in db_cols:
|
||||
print(f"⚠️ HIÁNYZÓ OSZLOP: {sc}.{t_name}.{col.name}")
|
||||
mismatches += 1
|
||||
suggestions.append(f"ALTER TABLE {sc}.{t_name} ADD COLUMN {col.name} {col.type};")
|
||||
else:
|
||||
# MÉLY TÍPUS ELLENŐRZÉS
|
||||
db_col = db_cols[col.name]
|
||||
db_type_str = str(db_col['type']).upper()
|
||||
|
||||
# 1. JSONB Ellenőrzés
|
||||
if isinstance(col.type, JSONB) and "JSONB" not in db_type_str:
|
||||
print(f"🔬 TÍPUS ELTÉRÉS [JSONB]: {sc}.{t_name}.{col.name} (DB: {db_type_str})")
|
||||
mismatches += 1
|
||||
|
||||
# 2. NUMERIC Precizitás
|
||||
elif isinstance(col.type, NUMERIC):
|
||||
m_prec, m_scale = col.type.precision, col.type.scale
|
||||
d_prec, d_scale = db_col['type'].precision, db_col['type'].scale
|
||||
if m_prec != d_prec or m_scale != d_scale:
|
||||
print(f"🔬 TÍPUS ELTÉRÉS [NUMERIC]: {sc}.{t_name}.{col.name} (Kód: {m_prec},{m_scale} vs DB: {d_prec},{d_scale})")
|
||||
mismatches += 1
|
||||
|
||||
# 3. ENUM Ellenőrzés
|
||||
elif isinstance(col.type, ENUM):
|
||||
enum_name = col.type.name
|
||||
res = await conn.execute(text(
|
||||
"SELECT EXISTS (SELECT 1 FROM pg_type WHERE typname = :name)"),
|
||||
{"name": enum_name}
|
||||
)
|
||||
if not res.scalar():
|
||||
print(f"🔬 HIÁNYZÓ ENUM TÍPUS: {enum_name} ({sc}.{t_name}.{col.name})")
|
||||
mismatches += 1
|
||||
|
||||
print(f"✅ {sc}.{t_name:30} | Átvizsgálva.")
|
||||
|
||||
print("\n" + "="*50)
|
||||
if mismatches == 0:
|
||||
print("✨ GRATULÁLOK! A fájlrendszer és az adatbázis szinkronban van. ✨")
|
||||
else:
|
||||
print(f"⚠️ ÖSSZESEN {mismatches} ELTÉRÉS TALÁLHATÓ!")
|
||||
print("\nJAVÍTÁSI JAVASLATOK (Copy-Paste SQL):")
|
||||
for s in suggestions:
|
||||
print(f" {s}")
|
||||
print("="*50 + "\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_unified_audit())
|
||||
Reference in New Issue
Block a user