Spaces:
Running
Running
| import os | |
| import psycopg2 | |
| import logging | |
| logger = logging.getLogger("customercore.db.migrations") | |
| def run_db_migrations(): | |
| """ | |
| Checks if tickets table has missing columns and updates it. | |
| Also notifies PostgREST to reload its schema cache. | |
| Fails gracefully if the database is unreachable (e.g., in IPv6-unsupported environments). | |
| """ | |
| db_url = os.environ.get("SUPABASE_DB_URL") | |
| if not db_url: | |
| logger.warning("SUPABASE_DB_URL is not set. Skipping DDL migrations.") | |
| return | |
| import urllib.parse | |
| if "://" in db_url and "@" in db_url: | |
| try: | |
| prefix, rest = db_url.split("://", 1) | |
| creds_part, host_part = rest.rsplit("@", 1) | |
| if ":" in creds_part: | |
| user, password = creds_part.split(":", 1) | |
| unquoted_password = urllib.parse.unquote(password) | |
| encoded_password = urllib.parse.quote_plus(unquoted_password) | |
| db_url = f"{prefix}://{user}:{encoded_password}@{host_part}" | |
| except Exception as parse_err: | |
| logger.warning(f"Failed to pre-parse SUPABASE_DB_URL: {parse_err}") | |
| logger.info("Running database migration checks...") | |
| try: | |
| # Connect to Postgres | |
| conn = psycopg2.connect(db_url, connect_timeout=5) | |
| conn.autocommit = True | |
| cursor = conn.cursor() | |
| # Add columns if not present | |
| cursor.execute(""" | |
| ALTER TABLE tickets | |
| ADD COLUMN IF NOT EXISTS customer_tier TEXT NOT NULL DEFAULT 'free' | |
| CHECK (customer_tier IN ('free','starter','growth','enterprise','vip')); | |
| """) | |
| cursor.execute(""" | |
| ALTER TABLE tickets | |
| ADD COLUMN IF NOT EXISTS masked_text TEXT; | |
| """) | |
| # Reload PostgREST schema cache | |
| cursor.execute("SELECT pg_notify('pgrst', 'reload schema');") | |
| logger.info("Database migration check completed successfully. PostgREST schema reloaded.") | |
| cursor.close() | |
| conn.close() | |
| except psycopg2.OperationalError as oe: | |
| # Graceful fallback: log warning and continue so local app startup does not crash | |
| logger.warning( | |
| "Database connection timed out or unreachable (normal in local environments without IPv6 routing). " | |
| f"Details: {oe}" | |
| ) | |
| except Exception as e: | |
| logger.error(f"Failed to execute database migrations: {e}") | |