70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
from fastapi import APIRouter, HTTPException
|
|
import pkgutil
|
|
import importlib
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
from bd import Settings
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
router = APIRouter(tags=["db"])
|
|
|
|
|
|
def _iter_table_modules() -> List[str]:
|
|
try:
|
|
import bd.tables as tables_pkg
|
|
pkg_paths = getattr(tables_pkg, "__path__", None)
|
|
if not pkg_paths:
|
|
pkg_paths = [str(Path(__file__).resolve().parent.parent / "bd" / "tables")]
|
|
except Exception:
|
|
pkg_paths = [str(Path(__file__).resolve().parent.parent / "bd" / "tables")]
|
|
|
|
names = []
|
|
for finder, name, ispkg in pkgutil.iter_modules(pkg_paths):
|
|
names.append(name)
|
|
return names
|
|
|
|
|
|
def collect_metadatas():
|
|
metadatas = []
|
|
for mod_name in _iter_table_modules():
|
|
try:
|
|
module = importlib.import_module(f"bd.tables.{mod_name}")
|
|
except Exception:
|
|
continue
|
|
Base = getattr(module, "Base", None)
|
|
if Base is not None and hasattr(Base, "metadata"):
|
|
metadatas.append(Base.metadata)
|
|
return metadatas
|
|
|
|
|
|
@router.post("/db/create-tables")
|
|
async def create_tables():
|
|
"""Создаёт все таблицы, описанные в модулях `db.tables`.
|
|
|
|
Endpoint вызывается по нажатию кнопки в UI (POST).
|
|
"""
|
|
settings = Settings()
|
|
db_url = settings.DATABASE_URL_syncpg
|
|
engine = create_engine(db_url, future=True)
|
|
|
|
metadatas = collect_metadatas()
|
|
if not metadatas:
|
|
raise HTTPException(status_code=400, detail="No table metadata found in db.tables")
|
|
|
|
# deduplicate metadata objects (multiple modules may expose the same Base.metadata)
|
|
unique = []
|
|
seen = set()
|
|
for md in metadatas:
|
|
if id(md) not in seen:
|
|
seen.add(id(md))
|
|
unique.append(md)
|
|
|
|
try:
|
|
for md in unique:
|
|
md.create_all(bind=engine)
|
|
return {"status": "ok", "detail": f"Created {len(unique)} metadata groups"}
|
|
except SQLAlchemyError as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|