104 lines
2.9 KiB
Python
Executable File
104 lines
2.9 KiB
Python
Executable File
"""Migration: Add custom_fields column to customers table.
|
|
|
|
Sprint 6.6: Enable dynamic WordPress field synchronization.
|
|
|
|
This migration adds a TEXT column for storing JSON-encoded custom fields
|
|
from WordPress booking forms, enabling automatic synchronization without
|
|
schema changes.
|
|
|
|
Usage:
|
|
python -m customer_portal.migrations.001_add_custom_fields
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
from sqlalchemy import create_engine, inspect, text
|
|
|
|
|
|
def get_database_url() -> str:
|
|
"""Get database URL from environment."""
|
|
return os.getenv(
|
|
"DATABASE_URL",
|
|
os.getenv(
|
|
"SQLALCHEMY_DATABASE_URI",
|
|
"sqlite:///customer_portal.db",
|
|
),
|
|
)
|
|
|
|
|
|
def migrate():
|
|
"""Add custom_fields column to customers table."""
|
|
database_url = get_database_url()
|
|
engine = create_engine(database_url)
|
|
|
|
inspector = inspect(engine)
|
|
columns = [col["name"] for col in inspector.get_columns("customers")]
|
|
|
|
if "custom_fields" in columns:
|
|
print("Column 'custom_fields' already exists. Skipping.")
|
|
return True
|
|
|
|
print("Adding 'custom_fields' column to customers table...")
|
|
|
|
# Detect database type for appropriate SQL
|
|
dialect = engine.dialect.name
|
|
|
|
with engine.begin() as conn:
|
|
if dialect in {"sqlite", "postgresql"}:
|
|
conn.execute(
|
|
text("ALTER TABLE customers ADD COLUMN custom_fields TEXT DEFAULT '{}'")
|
|
)
|
|
elif dialect == "mysql":
|
|
conn.execute(text("ALTER TABLE customers ADD COLUMN custom_fields TEXT"))
|
|
conn.execute(
|
|
text(
|
|
"UPDATE customers SET custom_fields = '{}' WHERE custom_fields IS NULL"
|
|
)
|
|
)
|
|
else:
|
|
# Generic SQL
|
|
conn.execute(
|
|
text("ALTER TABLE customers ADD COLUMN custom_fields TEXT DEFAULT '{}'")
|
|
)
|
|
|
|
print("Migration completed successfully.")
|
|
return True
|
|
|
|
|
|
def rollback():
|
|
"""Remove custom_fields column (if needed)."""
|
|
database_url = get_database_url()
|
|
engine = create_engine(database_url)
|
|
|
|
inspector = inspect(engine)
|
|
columns = [col["name"] for col in inspector.get_columns("customers")]
|
|
|
|
if "custom_fields" not in columns:
|
|
print("Column 'custom_fields' does not exist. Skipping rollback.")
|
|
return True
|
|
|
|
print("WARNING: Rolling back will DELETE all custom field data!")
|
|
|
|
dialect = engine.dialect.name
|
|
|
|
with engine.begin() as conn:
|
|
if dialect == "sqlite":
|
|
# SQLite doesn't support DROP COLUMN directly
|
|
print("SQLite does not support DROP COLUMN. Manual migration required.")
|
|
return False
|
|
else:
|
|
conn.execute(text("ALTER TABLE customers DROP COLUMN custom_fields"))
|
|
|
|
print("Rollback completed.")
|
|
return True
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1 and sys.argv[1] == "--rollback":
|
|
success = rollback()
|
|
else:
|
|
success = migrate()
|
|
|
|
sys.exit(0 if success else 1)
|