Update database setup to include simple migrations and enhance .gitignore
- Added the `run_simple_migrations` function call in the database initialization process to ensure any missing columns are added during setup. - Updated the .gitignore file to exclude the `models_old.py` file, improving project cleanliness.
This commit is contained in:
@@ -16,3 +16,4 @@ __pycache__/
|
||||
*.pid
|
||||
locales/ru_backup.json
|
||||
locales/en_backup.json
|
||||
db/models_old.py
|
||||
|
||||
@@ -4,6 +4,7 @@ from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from config.settings import Settings
|
||||
from .models import Base
|
||||
from .migrator import run_simple_migrations
|
||||
|
||||
async_engine = None
|
||||
|
||||
@@ -62,6 +63,8 @@ async def init_db(settings: Settings, session_factory: sessionmaker):
|
||||
|
||||
async with async_engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
# Run lightweight, idempotent migrations to add any missing columns
|
||||
await conn.run_sync(run_simple_migrations)
|
||||
logging.info(
|
||||
"PostgreSQL database initialized/checked successfully using SQLAlchemy."
|
||||
)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import logging
|
||||
from typing import Set
|
||||
|
||||
from sqlalchemy import inspect, text
|
||||
from sqlalchemy.engine import Connection
|
||||
|
||||
from .models import Base
|
||||
|
||||
|
||||
def _add_missing_columns(connection: Connection) -> None:
|
||||
inspector = inspect(connection)
|
||||
metadata = Base.metadata
|
||||
|
||||
existing_tables: Set[str] = set(inspector.get_table_names())
|
||||
|
||||
for table in metadata.tables.values():
|
||||
table_name = table.name
|
||||
if table_name not in existing_tables:
|
||||
# Tables are created elsewhere via create_all; skip here.
|
||||
continue
|
||||
|
||||
existing_columns = {col_info["name"] for col_info in inspector.get_columns(table_name)}
|
||||
|
||||
for desired_column in table.columns:
|
||||
if desired_column.name in existing_columns:
|
||||
continue
|
||||
|
||||
# Build ADD COLUMN DDL
|
||||
preparer = connection.dialect.identifier_preparer
|
||||
table_quoted = preparer.format_table(table)
|
||||
column_name_quoted = preparer.quote(desired_column.name)
|
||||
column_type_sql = desired_column.type.compile(dialect=connection.dialect)
|
||||
|
||||
default_clause = ""
|
||||
server_default = getattr(desired_column, "server_default", None)
|
||||
if server_default is not None and getattr(server_default, "arg", None) is not None:
|
||||
try:
|
||||
compiled_default = str(
|
||||
server_default.arg.compile(dialect=connection.dialect)
|
||||
)
|
||||
default_clause = f" DEFAULT {compiled_default}"
|
||||
except Exception: # best-effort
|
||||
pass
|
||||
|
||||
# For safety, add new columns as NULLable to avoid failures on existing rows
|
||||
# If strict NOT NULL is needed, it can be enforced manually later.
|
||||
ddl = f"ALTER TABLE {table_quoted} ADD COLUMN {column_name_quoted} {column_type_sql}{default_clause}"
|
||||
|
||||
logging.info(
|
||||
f"Migrator: adding missing column {desired_column.name} to table {table_name}"
|
||||
)
|
||||
connection.execute(text(ddl))
|
||||
|
||||
|
||||
def run_simple_migrations(connection: Connection) -> None:
|
||||
"""
|
||||
Run lightweight, idempotent migrations:
|
||||
- Ensure missing columns are added to existing tables to match models in db/models.py
|
||||
Note: Table creation is handled separately via Base.metadata.create_all.
|
||||
"""
|
||||
try:
|
||||
_add_missing_columns(connection)
|
||||
logging.info("Migrator: schema synchronized (columns added as needed).")
|
||||
except Exception as e:
|
||||
logging.error(f"Migrator: failed to run simple migrations: {e}", exc_info=True)
|
||||
raise
|
||||
Reference in New Issue
Block a user