""" 自動數據庫遷移 - 添加修正追踪欄位 在應用啟動時執行 """ import os from psycopg import connect def run_auto_migration(): """自動遷移:添加修正追踪欄位""" try: conn = connect( host=os.getenv("DB_HOST"), port=int(os.getenv("DB_PORT")), dbname=os.getenv("DB_NAME"), user=os.getenv("DB_USER"), password=os.getenv("DB_PASSWORD"), ) with conn.cursor() as cur: print("\n" + "=" * 80) print("【自動數據庫遷移】") print("=" * 80) # 1. 添加 is_latest 欄位 print("\n【步驟 1】檢查 is_latest 欄位...") try: cur.execute(""" SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'journal_entries' AND column_name = 'is_latest' """) if cur.fetchone()[0] == 0: # 欄位不存在,添加 try: cur.execute(""" ALTER TABLE journal_entries ADD COLUMN is_latest BOOLEAN DEFAULT true """) conn.commit() print("✓ 欄位 is_latest 已添加") except Exception as e: conn.rollback() print(f"⚠️ 無法添加 is_latest(可能由於權限): {e}") else: print("✓ 欄位 is_latest 已存在") except Exception as e: print(f"⚠️ 檢查 is_latest 失敗: {e}") # 2. 添加 revision_count 欄位 print("\n【步驟 2】檢查 revision_count 欄位...") try: cur.execute(""" SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'journal_entries' AND column_name = 'revision_count' """) if cur.fetchone()[0] == 0: try: cur.execute(""" ALTER TABLE journal_entries ADD COLUMN revision_count INTEGER DEFAULT 1 """) conn.commit() print("✓ 欄位 revision_count 已添加") except Exception as e: conn.rollback() print(f"⚠️ 無法添加 revision_count(可能由於權限): {e}") else: print("✓ 欄位 revision_count 已存在") except Exception as e: print(f"⚠️ 檢查 revision_count 失敗: {e}") # 3. 添加 original_entry_id 欄位 print("\n【步驟 3】檢查 original_entry_id 欄位...") try: cur.execute(""" SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'journal_entries' AND column_name = 'original_entry_id' """) if cur.fetchone()[0] == 0: try: cur.execute(""" ALTER TABLE journal_entries ADD COLUMN original_entry_id INTEGER """) conn.commit() print("✓ 欄位 original_entry_id 已添加") except Exception as e: conn.rollback() print(f"⚠️ 無法添加 original_entry_id(可能由於權限): {e}") else: print("✓ 欄位 original_entry_id 已存在") except Exception as e: print(f"⚠️ 檢查 original_entry_id 失敗: {e}") # 4. 創建索引 print("\n【步驟 4】創建索引...") try: cur.execute(""" CREATE INDEX IF NOT EXISTS idx_journal_entries_is_latest ON journal_entries(is_latest, entry_date) """) conn.commit() print("✓ 索引 idx_journal_entries_is_latest 已創建") except Exception as e: print(f"⚠️ 無法創建索引: {e}") # 5. 驗證 print("\n【步驟 5】驗證新欄位...") try: cur.execute(""" SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'journal_entries' AND column_name IN ('is_latest', 'revision_count', 'original_entry_id') ORDER BY ordinal_position """) rows = cur.fetchall() if rows: for row in rows: col_name = row[0] data_type = row[1] print(f" ✓ {col_name}: {data_type}") else: print(" ℹ️ 新欄位尚未存在(需要管理員執行遷移 SQL)") except Exception as e: print(f"⚠️ 驗證失敗: {e}") print("\n" + "=" * 80) print("✓ 自動遷移檢查完成!") print("=" * 80 + "\n") conn.close() except Exception as e: print(f"\n❌ 無法連接到數據庫或執行遷移: {e}") print("\n提示:") print("1. 確認數據庫連接信息正確(DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD)") print("2. 如果字段仍不存在,請使用管理員帳戶執行以下 SQL 命令:") print(""" ALTER TABLE journal_entries ADD COLUMN IF NOT EXISTS is_latest BOOLEAN DEFAULT true; ALTER TABLE journal_entries ADD COLUMN IF NOT EXISTS revision_count INTEGER DEFAULT 1; ALTER TABLE journal_entries ADD COLUMN IF NOT EXISTS original_entry_id INTEGER; CREATE INDEX IF NOT EXISTS idx_journal_entries_is_latest ON journal_entries(is_latest, entry_date); """) if __name__ == "__main__": run_auto_migration()