From 6f271f8c30a197b4c76c8712c2d5b40b4adb8f54 Mon Sep 17 00:00:00 2001 From: Sanjay Padole Date: Wed, 26 Aug 2026 11:39:31 -0500 Subject: [PATCH] Internal Database Fix --- app/database.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/database.py b/app/database.py index 5178f22..710da6d 100644 --- a/app/database.py +++ b/app/database.py @@ -12,11 +12,11 @@ needs to change. """ from __future__ import annotations -from sqlalchemy import create_engine +from sqlalchemy import create_engine, inspect, text from sqlalchemy.orm import sessionmaker, Session from app import config -from app.models import Base +from app.models import Base, Order _engine = None _SessionLocal = None @@ -42,8 +42,34 @@ def get_session_factory(): def init_db() -> None: - """Create tables that don't exist yet. Safe to call every startup.""" - Base.metadata.create_all(get_engine()) + """Create tables that don't exist yet, and patch existing ones with + any columns added to the model since they were created. Safe to call + every startup - this is a local cache rebuilt from JIRA/ShipStation, + not a system of record, so a simple additive auto-migration is + enough; we don't need a full migration framework for it.""" + engine = get_engine() + Base.metadata.create_all(engine) + _add_missing_columns(engine) + + +def _add_missing_columns(engine) -> None: + inspector = inspect(engine) + if "orders" not in inspector.get_table_names(): + return # create_all() just made it fresh - nothing to patch + + existing_columns = {col["name"] for col in inspector.get_columns("orders")} + missing = [c for c in Order.__table__.columns if c.name not in existing_columns] + if not missing: + return + + with engine.begin() as conn: + for column in missing: + col_type = column.type.compile(dialect=engine.dialect) + # Always added as nullable, regardless of what the model says - + # existing rows get backfilled with real values the next time + # they're touched by an import, and this avoids ALTER TABLE + # failing on a NOT NULL column with no default for old rows. + conn.execute(text(f'ALTER TABLE orders ADD COLUMN "{column.name}" {col_type}')) def get_session() -> Session: