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:
machka-pasla
2025-09-04 19:52:57 +03:00
parent f11ec6a676
commit 807e3dadd3
3 changed files with 70 additions and 0 deletions
+1
View File
@@ -16,3 +16,4 @@ __pycache__/
*.pid
locales/ru_backup.json
locales/en_backup.json
db/models_old.py
+3
View File
@@ -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."
)
+66
View File
@@ -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