gabriel / musehub public
env.py python
106 lines 3.0 KB
cd448303 Initial extraction of MuseHub from maestro monorepo. Gabriel Cardona <gabriel@tellurstori.com> 7d ago
1 """Alembic environment configuration for Maestro."""
2 from __future__ import annotations
3
4 import asyncio
5 from logging.config import fileConfig
6
7 from sqlalchemy import pool
8 from sqlalchemy.engine import Connection
9 from sqlalchemy.ext.asyncio import async_engine_from_config
10
11 from alembic import context
12
13 # Import your models' Base
14 from musehub.db.database import Base
15 from musehub.db import models # noqa: F401 - Import to register models
16 from musehub.db import muse_cli_models # noqa: F401 - Register Muse CLI commit tables (retained for MuseHub)
17 from musehub.config import settings
18
19 # Alembic Config object
20 config = context.config
21
22 # Interpret the config file for Python logging
23 if config.config_file_name is not None:
24 fileConfig(config.config_file_name)
25
26 # Add your model's MetaData object here for 'autogenerate' support
27 target_metadata = Base.metadata
28
29 # Override sqlalchemy.url with the one from settings (required; no default password in repo)
30 if not settings.database_url:
31 raise RuntimeError(
32 "DATABASE_URL (or DB_PASSWORD with Docker Postgres) must be set for migrations. "
33 "set in .env or export before running alembic."
34 )
35 config.set_main_option(
36 "sqlalchemy.url",
37 settings.database_url.replace("+aiosqlite", "").replace("+asyncpg", ""),
38 )
39
40
41 def run_migrations_offline() -> None:
42 """Run migrations in 'offline' mode.
43
44 This configures the context with just a URL
45 and not an Engine, though an Engine is acceptable
46 here as well. By skipping the Engine creation
47 we don't even need a DBAPI to be available.
48
49 Calls to context.execute() here emit the given string to the
50 script output.
51 """
52 url = config.get_main_option("sqlalchemy.url")
53 context.configure(
54 url=url,
55 target_metadata=target_metadata,
56 literal_binds=True,
57 dialect_opts={"paramstyle": "named"},
58 compare_type=True,
59 compare_server_default=True,
60 )
61
62 with context.begin_transaction():
63 context.run_migrations()
64
65
66 def do_run_migrations(connection: Connection) -> None:
67 """Run migrations with a connection."""
68 context.configure(
69 connection=connection,
70 target_metadata=target_metadata,
71 compare_type=True,
72 compare_server_default=True,
73 )
74
75 with context.begin_transaction():
76 context.run_migrations()
77
78
79 async def run_async_migrations() -> None:
80 """Run migrations in 'online' mode with async support."""
81 configuration = config.get_section(config.config_ini_section, {})
82
83 # Use the database URL from settings
84 configuration["sqlalchemy.url"] = settings.database_url
85
86 connectable = async_engine_from_config(
87 configuration,
88 prefix="sqlalchemy.",
89 poolclass=pool.NullPool,
90 )
91
92 async with connectable.connect() as connection:
93 await connection.run_sync(do_run_migrations)
94
95 await connectable.dispose()
96
97
98 def run_migrations_online() -> None:
99 """Run migrations in 'online' mode."""
100 asyncio.run(run_async_migrations())
101
102
103 if context.is_offline_mode():
104 run_migrations_offline()
105 else:
106 run_migrations_online()