summaryrefslogtreecommitdiff
path: root/shared/alembic
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:00:38 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:02:03 +0900
commit2b1db156c7ea7e0be543ab91813922b95eb043cb (patch)
treefd19abb0845d96e160c68817190b33a0f6c0034d /shared/alembic
parent33b14aaa2344b0fd95d1629627c3d135b24ae102 (diff)
feat: add SQLAlchemy ORM models and Alembic migration setup
Add SA 2.0 declarative models (CandleRow, SignalRow, OrderRow, TradeRow, PositionRow, PortfolioSnapshotRow) mirroring existing asyncpg tables. Set up Alembic with async PostgreSQL support and add migrate/migrate-down/ migrate-new Makefile targets. Update shared dependencies with sqlalchemy, alembic, structlog, prometheus-client, pyyaml, aiohttp, and rich.
Diffstat (limited to 'shared/alembic')
-rw-r--r--shared/alembic/env.py66
-rw-r--r--shared/alembic/script.py.mako26
-rw-r--r--shared/alembic/versions/.gitkeep0
3 files changed, 92 insertions, 0 deletions
diff --git a/shared/alembic/env.py b/shared/alembic/env.py
new file mode 100644
index 0000000..14303f6
--- /dev/null
+++ b/shared/alembic/env.py
@@ -0,0 +1,66 @@
+"""Alembic environment configuration for async PostgreSQL migrations."""
+
+import asyncio
+from logging.config import fileConfig
+
+from alembic import context
+from sqlalchemy import pool
+from sqlalchemy.ext.asyncio import async_engine_from_config
+
+from shared.sa_models import Base
+
+config = context.config
+
+if config.config_file_name is not None:
+ fileConfig(config.config_file_name)
+
+target_metadata = Base.metadata
+
+
+def run_migrations_offline() -> None:
+ """Run migrations in 'offline' mode.
+
+ Configures the context with just a URL and not an Engine.
+ Calls to context.execute() here emit the given string to the script output.
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(
+ url=url,
+ target_metadata=target_metadata,
+ literal_binds=True,
+ dialect_opts={"paramstyle": "named"},
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def do_run_migrations(connection):
+ context.configure(connection=connection, target_metadata=target_metadata)
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+async def run_async_migrations() -> None:
+ """Run migrations in 'online' mode using an async engine."""
+ connectable = async_engine_from_config(
+ config.get_section(config.config_ini_section, {}),
+ prefix="sqlalchemy.",
+ poolclass=pool.NullPool,
+ )
+
+ async with connectable.connect() as connection:
+ await connection.run_sync(do_run_migrations)
+
+ await connectable.dispose()
+
+
+def run_migrations_online() -> None:
+ """Run migrations in 'online' mode."""
+ asyncio.run(run_async_migrations())
+
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/shared/alembic/script.py.mako b/shared/alembic/script.py.mako
new file mode 100644
index 0000000..fbc4b07
--- /dev/null
+++ b/shared/alembic/script.py.mako
@@ -0,0 +1,26 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision: str = ${repr(up_revision)}
+down_revision: Union[str, None] = ${repr(down_revision)}
+branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
+depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
+
+
+def upgrade() -> None:
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade() -> None:
+ ${downgrades if downgrades else "pass"}
diff --git a/shared/alembic/versions/.gitkeep b/shared/alembic/versions/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/alembic/versions/.gitkeep