Big-Link-Man/scripts/migrate_story_3.2.py

216 lines
6.6 KiB
Python

"""
Database migration for Story 3.2: Find Tiered Links
This script adds:
1. money_site_url column to projects table
2. article_links table for tracking link relationships
Run this script BEFORE deploying Story 3.2 code to production.
Usage:
python scripts/migrate_story_3.2.py
"""
import sys
from pathlib import Path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from sqlalchemy import text, inspect
from src.database.session import db_manager
from src.core.config import get_config
def check_column_exists(inspector, table_name: str, column_name: str) -> bool:
"""Check if a column exists in a table"""
columns = inspector.get_columns(table_name)
return any(col['name'] == column_name for col in columns)
def check_table_exists(inspector, table_name: str) -> bool:
"""Check if a table exists"""
return table_name in inspector.get_table_names()
def migrate_add_money_site_url(connection):
"""Add money_site_url column to projects table"""
print("\n[1/2] Adding money_site_url to projects table...")
inspector = inspect(connection)
if not check_table_exists(inspector, 'projects'):
print(" [ERROR] projects table does not exist!")
return False
if check_column_exists(inspector, 'projects', 'money_site_url'):
print(" [INFO] Column money_site_url already exists, skipping")
return True
try:
connection.execute(text("""
ALTER TABLE projects ADD COLUMN money_site_url VARCHAR(500) NULL
"""))
print(" [OK] Added money_site_url column")
connection.execute(text("""
CREATE INDEX idx_projects_money_site_url ON projects(money_site_url)
"""))
print(" [OK] Created index on money_site_url")
connection.commit()
return True
except Exception as e:
print(f" [ERROR] {e}")
connection.rollback()
return False
def migrate_create_article_links_table(connection):
"""Create article_links table"""
print("\n[2/2] Creating article_links table...")
inspector = inspect(connection)
if check_table_exists(inspector, 'article_links'):
print(" [INFO] Table article_links already exists, skipping")
return True
try:
connection.execute(text("""
CREATE TABLE article_links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
from_content_id INTEGER NOT NULL,
to_content_id INTEGER NULL,
to_url TEXT NULL,
link_type VARCHAR(20) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (from_content_id) REFERENCES generated_content(id) ON DELETE CASCADE,
FOREIGN KEY (to_content_id) REFERENCES generated_content(id) ON DELETE CASCADE,
CHECK (to_content_id IS NOT NULL OR to_url IS NOT NULL)
)
"""))
print(" [OK] Created article_links table")
connection.execute(text("""
CREATE INDEX idx_article_links_from ON article_links(from_content_id)
"""))
print(" [OK] Created index on from_content_id")
connection.execute(text("""
CREATE INDEX idx_article_links_to ON article_links(to_content_id)
"""))
print(" [OK] Created index on to_content_id")
connection.execute(text("""
CREATE INDEX idx_article_links_type ON article_links(link_type)
"""))
print(" [OK] Created index on link_type")
connection.commit()
return True
except Exception as e:
print(f" [ERROR] {e}")
connection.rollback()
return False
def verify_migration(connection):
"""Verify the migration was successful"""
print("\n[Verification] Checking migration results...")
inspector = inspect(connection)
success = True
if check_column_exists(inspector, 'projects', 'money_site_url'):
print(" [OK] projects.money_site_url exists")
else:
print(" [ERROR] projects.money_site_url MISSING")
success = False
if check_table_exists(inspector, 'article_links'):
print(" [OK] article_links table exists")
columns = inspector.get_columns('article_links')
expected_columns = ['id', 'from_content_id', 'to_content_id', 'to_url', 'link_type', 'created_at']
actual_columns = [col['name'] for col in columns]
for col in expected_columns:
if col in actual_columns:
print(f" [OK] article_links.{col} exists")
else:
print(f" [ERROR] article_links.{col} MISSING")
success = False
indexes = inspector.get_indexes('article_links')
index_names = [idx['name'] for idx in indexes]
print(f" [INFO] Indexes: {index_names}")
else:
print(" [ERROR] article_links table MISSING")
success = False
return success
def main():
"""Run the migration"""
print("=" * 60)
print("Story 3.2 Database Migration")
print("=" * 60)
try:
config = get_config()
print(f"\nDatabase: {config.database.url}")
except Exception as e:
print(f"[ERROR] Error loading configuration: {e}")
sys.exit(1)
try:
db_manager.initialize()
engine = db_manager.get_engine()
connection = engine.connect()
except Exception as e:
print(f"[ERROR] Error connecting to database: {e}")
sys.exit(1)
try:
success = True
if not migrate_add_money_site_url(connection):
success = False
if not migrate_create_article_links_table(connection):
success = False
if success:
if verify_migration(connection):
print("\n" + "=" * 60)
print("[SUCCESS] Migration completed successfully!")
print("=" * 60)
else:
print("\n" + "=" * 60)
print("[WARNING] Migration completed with warnings")
print("=" * 60)
else:
print("\n" + "=" * 60)
print("[FAILED] Migration failed!")
print("=" * 60)
sys.exit(1)
except Exception as e:
print(f"\n[ERROR] Unexpected error during migration: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
finally:
connection.close()
db_manager.close()
if __name__ == "__main__":
main()