""" Rotina dedicada de bootstrap de banco de dados. Cria tabelas e executa seed inicial de forma explicita, fora do startup do app. """ from pathlib import Path from sqlalchemy import inspect, text from app.core.settings import settings from app.db.database import Base, engine from app.db.mock_database import MockBase, mock_engine from app.db.models import Tool from app.db.mock_models import ( ConversationTurn, Customer, IntegrationDelivery, IntegrationRoute, Order, RentalContract, RentalPayment, RentalVehicle, ReviewSchedule, Vehicle, ) from app.db.mock_seed import seed_mock_data from app.db.tool_seed import seed_tools from shared.contracts import GENERATED_TOOLS_PACKAGE _PROJECT_ROOT = Path(__file__).resolve().parents[2] def _ensure_generated_tools_runtime_package() -> Path: package_dir = _PROJECT_ROOT / GENERATED_TOOLS_PACKAGE package_dir.mkdir(parents=True, exist_ok=True) init_file = package_dir / "__init__.py" if not init_file.exists(): init_file.write_text( '"""Isolated runtime package for admin-governed generated tools."""\n', encoding="utf-8", ) return package_dir def _ensure_mock_schema_evolution() -> None: inspector = inspect(mock_engine) table_names = set(inspector.get_table_names()) if "users" in table_names: user_columns = {column["name"] for column in inspector.get_columns("users")} if "email" not in user_columns: with mock_engine.begin() as connection: connection.execute(text("ALTER TABLE users ADD COLUMN email VARCHAR(255)")) if "integration_deliveries" in table_names: delivery_columns = {column["name"] for column in inspector.get_columns("integration_deliveries")} statements: list[str] = [] if "recipient_email" not in delivery_columns: statements.append("ALTER TABLE integration_deliveries ADD COLUMN recipient_email VARCHAR(255)") if "recipient_name" not in delivery_columns: statements.append("ALTER TABLE integration_deliveries ADD COLUMN recipient_name VARCHAR(120)") if statements: with mock_engine.begin() as connection: for statement in statements: connection.execute(text(statement)) def bootstrap_databases( *, run_tools_seed: bool | None = None, run_mock_seed: bool | None = None, ) -> None: """Cria tabelas e executa seed inicial em ambos os bancos.""" print("Inicializando bancos...") failures: list[str] = [] try: generated_tools_dir = _ensure_generated_tools_runtime_package() print(f"Diretorio isolado de tools geradas pronto em {generated_tools_dir}.") except Exception as exc: print(f"Aviso: falha ao preparar diretorio isolado de tools geradas: {exc}") failures.append(f"generated_tools={exc}") should_seed_tools = settings.auto_seed_tools if run_tools_seed is None else bool(run_tools_seed) should_seed_mock = ( settings.auto_seed_mock and settings.mock_seed_enabled if run_mock_seed is None else bool(run_mock_seed) ) try: print("Criando tabelas MySQL (tools)...") Base.metadata.create_all(bind=engine) if should_seed_tools: print("Populando tools iniciais...") seed_tools() else: print("Seed de tools desabilitada por configuracao.") print("MySQL tools OK.") except Exception as exc: print(f"Aviso: falha no MySQL (tools): {exc}") failures.append(f"tools={exc}") try: print("Criando tabelas MySQL (dados ficticios)...") MockBase.metadata.create_all(bind=mock_engine) _ensure_mock_schema_evolution() if should_seed_mock: print("Populando dados ficticios iniciais...") seed_mock_data() else: print("Seed mock desabilitada por configuracao.") print("MySQL mock OK.") except Exception as exc: print(f"Aviso: falha no MySQL mock: {exc}") failures.append(f"mock={exc}") if failures: raise RuntimeError( "Falha ao inicializar bancos do orquestrador: " + " | ".join(failures) ) print("Bancos inicializados com sucesso!") def main() -> None: """Executa o bootstrap dedicado quando chamado via modulo.""" bootstrap_databases() if __name__ == "__main__": main()