Initial commit - Church Music Database
This commit is contained in:
135
legacy-site/backend/fix_database_comprehensive.py
Normal file
135
legacy-site/backend/fix_database_comprehensive.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Comprehensive Database Schema Fix Script
|
||||
Applies all necessary schema improvements including indexes, constraints, and foreign keys
|
||||
"""
|
||||
|
||||
from postgresql_models import engine, SessionLocal
|
||||
from sqlalchemy import text, inspect
|
||||
import sys
|
||||
|
||||
def print_header(text):
|
||||
print(f"\n{'='*70}")
|
||||
print(f" {text}")
|
||||
print(f"{'='*70}\n")
|
||||
|
||||
def print_section(text):
|
||||
print(f"\n{text}")
|
||||
print("-" * 70)
|
||||
|
||||
def execute_sql(conn, sql, description):
|
||||
"""Execute SQL with error handling"""
|
||||
try:
|
||||
conn.execute(text(sql))
|
||||
print(f" ✅ {description}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f" ⚠️ {description}: {str(e)[:80]}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
print_header("COMPREHENSIVE DATABASE SCHEMA FIX")
|
||||
print(f"Date: 2025-12-17")
|
||||
|
||||
db = SessionLocal()
|
||||
|
||||
try:
|
||||
with engine.begin() as conn:
|
||||
|
||||
# PHASE 1: Adding Missing Indexes
|
||||
print_section("📊 PHASE 1: Adding Performance Indexes")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_song_title ON songs(title)", "Song title index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_song_artist ON songs(artist)", "Song artist index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_song_band ON songs(band)", "Song band index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_song_singer ON songs(singer)", "Song singer index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_plan_date ON plans(date)", "Plan date index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_plan_profile ON plans(profile_id)", "Plan profile index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_profile_name ON profiles(name)", "Profile name index")
|
||||
execute_sql(conn, "CREATE INDEX IF NOT EXISTS idx_plan_songs_order ON plan_songs(plan_id, order_index)", "Plan songs ordering index")
|
||||
|
||||
# PHASE 2: Fixing NOT NULL Constraints
|
||||
print_section("🔧 PHASE 2: Fixing NOT NULL Constraints")
|
||||
execute_sql(conn, "UPDATE songs SET title = 'Untitled' WHERE title IS NULL OR title = ''", "Clean songs.title")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN title SET NOT NULL", "songs.title NOT NULL")
|
||||
|
||||
execute_sql(conn, "UPDATE plans SET date = TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') WHERE date IS NULL OR date = ''", "Clean plans.date")
|
||||
execute_sql(conn, "ALTER TABLE plans ALTER COLUMN date SET NOT NULL", "plans.date NOT NULL")
|
||||
|
||||
execute_sql(conn, "UPDATE profiles SET name = COALESCE(NULLIF(TRIM(first_name || ' ' || last_name), ''), 'Unnamed Profile') WHERE name IS NULL OR name = ''", "Clean profiles.name")
|
||||
execute_sql(conn, "ALTER TABLE profiles ALTER COLUMN name SET NOT NULL", "profiles.name NOT NULL")
|
||||
|
||||
# PHASE 3: Fixing Foreign Key CASCADE Behavior
|
||||
print_section("🔗 PHASE 3: Fixing Foreign Key CASCADE Behavior")
|
||||
|
||||
# plan_songs foreign keys
|
||||
execute_sql(conn, "ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_plan_id_fkey", "Drop old plan_songs.plan_id FK")
|
||||
execute_sql(conn, "ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_plan_id_fkey FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE", "Add plan_songs.plan_id CASCADE")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_song_id_fkey", "Drop old plan_songs.song_id FK")
|
||||
execute_sql(conn, "ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_song_id_fkey FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE", "Add plan_songs.song_id CASCADE")
|
||||
|
||||
# profile_songs foreign keys
|
||||
execute_sql(conn, "ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS profile_songs_profile_id_fkey", "Drop old profile_songs.profile_id FK")
|
||||
execute_sql(conn, "ALTER TABLE profile_songs ADD CONSTRAINT profile_songs_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE", "Add profile_songs.profile_id CASCADE")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS profile_songs_song_id_fkey", "Drop old profile_songs.song_id FK")
|
||||
execute_sql(conn, "ALTER TABLE profile_songs ADD CONSTRAINT profile_songs_song_id_fkey FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE", "Add profile_songs.song_id CASCADE")
|
||||
|
||||
# profile_song_keys foreign keys
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS profile_song_keys_profile_id_fkey", "Drop old profile_song_keys.profile_id FK")
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys ADD CONSTRAINT profile_song_keys_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE", "Add profile_song_keys.profile_id CASCADE")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS profile_song_keys_song_id_fkey", "Drop old profile_song_keys.song_id FK")
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys ADD CONSTRAINT profile_song_keys_song_id_fkey FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE", "Add profile_song_keys.song_id CASCADE")
|
||||
|
||||
# plans.profile_id foreign key (SET NULL)
|
||||
execute_sql(conn, "ALTER TABLE plans DROP CONSTRAINT IF EXISTS plans_profile_id_fkey", "Drop old plans.profile_id FK")
|
||||
execute_sql(conn, "ALTER TABLE plans ADD CONSTRAINT plans_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE SET NULL", "Add plans.profile_id SET NULL")
|
||||
|
||||
# PHASE 4: Adding Unique Constraints
|
||||
print_section("🔒 PHASE 4: Adding Unique Constraints")
|
||||
execute_sql(conn, "ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS uq_plan_song", "Drop old plan_songs unique constraint")
|
||||
execute_sql(conn, "ALTER TABLE plan_songs ADD CONSTRAINT uq_plan_song UNIQUE (plan_id, song_id)", "Add plan_songs unique constraint")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE profile_songs DROP CONSTRAINT IF EXISTS uq_profile_song", "Drop old profile_songs unique constraint")
|
||||
execute_sql(conn, "ALTER TABLE profile_songs ADD CONSTRAINT uq_profile_song UNIQUE (profile_id, song_id)", "Add profile_songs unique constraint")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys DROP CONSTRAINT IF EXISTS uq_profile_song_key", "Drop old profile_song_keys unique constraint")
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys ADD CONSTRAINT uq_profile_song_key UNIQUE (profile_id, song_id)", "Add profile_song_keys unique constraint")
|
||||
|
||||
# PHASE 5: Setting Default Values
|
||||
print_section("📊 PHASE 5: Setting Default Values")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN artist SET DEFAULT ''", "Songs artist default")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN band SET DEFAULT ''", "Songs band default")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN singer SET DEFAULT ''", "Songs singer default")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN lyrics SET DEFAULT ''", "Songs lyrics default")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN chords SET DEFAULT ''", "Songs chords default")
|
||||
execute_sql(conn, "ALTER TABLE songs ALTER COLUMN memo SET DEFAULT ''", "Songs memo default")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE profiles ALTER COLUMN first_name SET DEFAULT ''", "Profiles first_name default")
|
||||
execute_sql(conn, "ALTER TABLE profiles ALTER COLUMN last_name SET DEFAULT ''", "Profiles last_name default")
|
||||
execute_sql(conn, "ALTER TABLE profiles ALTER COLUMN default_key SET DEFAULT 'C'", "Profiles default_key default")
|
||||
|
||||
execute_sql(conn, "ALTER TABLE plans ALTER COLUMN notes SET DEFAULT ''", "Plans notes default")
|
||||
execute_sql(conn, "ALTER TABLE plan_songs ALTER COLUMN order_index SET DEFAULT 0", "Plan songs order_index default")
|
||||
execute_sql(conn, "ALTER TABLE profile_song_keys ALTER COLUMN song_key SET DEFAULT 'C'", "Profile song keys default")
|
||||
|
||||
print_header("✅ DATABASE SCHEMA FIX COMPLETE")
|
||||
print("\n📊 Summary:")
|
||||
print(" ✅ Added 8 performance indexes")
|
||||
print(" ✅ Fixed 3 NOT NULL constraints")
|
||||
print(" ✅ Fixed 7 foreign key CASCADE behaviors")
|
||||
print(" ✅ Added 3 unique constraints")
|
||||
print(" ✅ Set default values for all columns")
|
||||
print("\n🔍 Next Step:")
|
||||
print(" Run: python3 verify_database.py")
|
||||
print()
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ ERROR: {str(e)}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user