""" Alembic Environment Configuration for Crypto Trading Bot Platform """ import os import sys from logging.config import fileConfig from pathlib import Path from sqlalchemy import engine_from_config from sqlalchemy import pool from alembic import context # Add project root to path for imports project_root = Path(__file__).parent.parent.parent sys.path.insert(0, str(project_root)) # Load environment variables from .env file if it exists try: from dotenv import load_dotenv env_file = project_root / '.env' if env_file.exists(): load_dotenv(env_file) except ImportError: # dotenv not available, proceed without it pass # Import our models and database configuration from database.models import Base from database.connection import DatabaseConfig # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config # Interpret the config file for Python logging. # This line sets up loggers basically. if config.config_file_name is not None: fileConfig(config.config_file_name) # add your model's MetaData object here # for 'autogenerate' support target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option") # ... etc. def get_database_url(): """Get database URL from environment variables""" # Use DATABASE_URL if set, otherwise construct from individual components url = os.getenv('DATABASE_URL') if url: return url # Fallback to constructing URL from components user = os.getenv('POSTGRES_USER', 'dashboard') password = os.getenv('POSTGRES_PASSWORD', '') host = os.getenv('POSTGRES_HOST', 'localhost') port = os.getenv('POSTGRES_PORT', '5434') database = os.getenv('POSTGRES_DB', 'dashboard') return f"postgresql://{user}:{password}@{host}:{port}/{database}" def run_migrations_offline() -> None: """Run migrations in 'offline' mode. This configures the context with just a URL and not an Engine, though an Engine is acceptable here as well. By skipping the Engine creation we don't even need a DBAPI to be available. Calls to context.execute() here emit the given string to the script output. """ url = get_database_url() context.configure( url=url, target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, compare_type=True, compare_server_default=True, render_as_batch=False, # PostgreSQL supports transactional DDL ) with context.begin_transaction(): context.run_migrations() def run_migrations_online() -> None: """Run migrations in 'online' mode. In this scenario we need to create an Engine and associate a connection with the context. """ # Override the sqlalchemy.url in the config with our environment-based URL config.set_main_option("sqlalchemy.url", get_database_url()) # Create engine with our database configuration db_config = DatabaseConfig() engine_config = config.get_section(config.config_ini_section) engine_config.update(db_config.get_engine_kwargs()) connectable = engine_from_config( engine_config, prefix="sqlalchemy.", poolclass=pool.NullPool, # Use NullPool for migrations to avoid connection issues ) with connectable.connect() as connection: context.configure( connection=connection, target_metadata=target_metadata, compare_type=True, compare_server_default=True, render_as_batch=False, # PostgreSQL supports transactional DDL transaction_per_migration=True, # Each migration in its own transaction ) with context.begin_transaction(): context.run_migrations() if context.is_offline_mode(): run_migrations_offline() else: run_migrations_online()