IOI-RUN / banco.py
Roudrigus's picture
Upload 82 files
0f0ef8d verified
raw
history blame
4 kB
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
import os
from dotenv import load_dotenv
import importlib
# 🔒 Caminho absoluto do projeto
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# Carrega variáveis de ambiente (.env) antes de ler DATABASE_URL
load_dotenv()
# ============================================================
# 🔀 SUPORTE A DOIS BANCOS (Produção/Teste) COM FALLBACK
# ============================================================
# Tentamos usar o roteador (db_router.py). Se não existir ainda,
# caímos no comportamento original usando apenas DATABASE_URL.
try:
from db_router import (
get_engine as _router_get_engine,
get_session_factory as _router_get_session_factory,
SessionLocal as _router_SessionLocal,
)
_HAS_ROUTER = True
except Exception:
_HAS_ROUTER = False
# 🔧 Fallback: mesma lógica do seu módulo original — um único DATABASE_URL
DATABASE_URL = os.getenv(
"DATABASE_URL",
f"sqlite:///{os.path.join(BASE_DIR, 'load.db')}"
)
engine_args = {
"echo": False,
"pool_pre_ping": True,
}
# Parâmetros específicos para SQLite (apenas se o fallback estiver ativo)
if DATABASE_URL.startswith("sqlite"):
engine_args["connect_args"] = {"check_same_thread": False}
# ============================================================
# Engine / SessionLocal (com ou sem roteador)
# ============================================================
if _HAS_ROUTER:
# ✅ Usa engine e SessionLocal do banco ATIVO (Produção/Teste), conforme escolha no login
def get_engine():
return _router_get_engine()
def _session_factory():
return _router_get_session_factory()
# A SessionLocal do roteador já entrega sessões no banco ativo
SessionLocal = _router_SessionLocal
else:
# ✅ Fallback: comportamento original com DATABASE_URL único
_engine = create_engine(DATABASE_URL, **engine_args)
def get_engine():
return _engine
_SessionFactory = sessionmaker(
autocommit=False,
autoflush=False,
bind=_engine,
)
def _session_factory():
return _SessionFactory
# Compatível com seu uso atual: SessionLocal() -> sessão
SessionLocal = _SessionFactory
# ⚠️ Compatibilidade: expõe 'engine' resolvendo via get_engine()
# Observação importante:
# - Se trocar o banco após a importação deste módulo (via login),
# prefira sempre chamar get_engine() ou criar sessões com SessionLocal(),
# pois 'engine' abaixo é resolvido apenas uma vez (na importação).
engine = get_engine()
# ORM Base
Base = declarative_base()
# ============================================================
# 🛠️ Utilitários (opcionais)
# ============================================================
def init_schema():
"""
Cria/atualiza as tabelas no banco ATIVO.
• Com roteador: aplica no banco escolhido (Produção/Teste).
• Sem roteador: aplica no DATABASE_URL padrão.
Use em DEV/TESTE; em produção, prefira migrações (ex.: Alembic).
"""
# Importa 'models' de forma tardia e segura (sem wildcard) para registrar todos os mapeamentos
# antes de criar as tabelas. Isso evita import circular no topo.
try:
importlib.import_module("models")
except ModuleNotFoundError:
# Se seus modelos estiverem em outro pacote/caminho, ajuste aqui:
# importlib.import_module("app.models") # exemplo
raise
Base.metadata.create_all(bind=get_engine())
def db_info() -> dict:
"""
Retorna informações básicas do banco ativo (para debug/UX).
"""
eng = get_engine()
try:
url = str(eng.url)
except Exception:
url = DATABASE_URL
return {
"url": url,
"using_router": _HAS_ROUTER,
}