194 lines
7.3 KiB
Python
194 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
修復 dt_translation_cache 資料表結構
|
||
|
||
問題:資料表欄位名稱與模型定義不一致
|
||
- content_hash → source_text_hash
|
||
- source_lang → source_language
|
||
- target_lang → target_language
|
||
"""
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
project_root = Path(__file__).parent.parent
|
||
sys.path.insert(0, str(project_root))
|
||
|
||
from app import create_app, db
|
||
from sqlalchemy import text
|
||
|
||
|
||
def run_migration():
|
||
app = create_app()
|
||
|
||
with app.app_context():
|
||
print("=" * 60)
|
||
print("修復 dt_translation_cache 資料表結構")
|
||
print("=" * 60)
|
||
|
||
try:
|
||
# 1. 檢查當前結構
|
||
print("\n[1/6] 檢查當前資料表結構...")
|
||
result = db.session.execute(text('SHOW COLUMNS FROM dt_translation_cache'))
|
||
current_columns = {row[0]: row for row in result}
|
||
print(f" ✓ 當前欄位: {', '.join(current_columns.keys())}")
|
||
|
||
# 2. 備份資料
|
||
print("\n[2/6] 備份現有資料...")
|
||
db.session.execute(text('''
|
||
CREATE TABLE IF NOT EXISTS dt_translation_cache_backup_20251001
|
||
AS SELECT * FROM dt_translation_cache
|
||
'''))
|
||
db.session.commit()
|
||
|
||
backup_count = db.session.execute(
|
||
text('SELECT COUNT(*) FROM dt_translation_cache_backup_20251001')
|
||
).scalar()
|
||
print(f" ✓ 已備份 {backup_count} 筆記錄")
|
||
|
||
# 3. 重新命名欄位:content_hash → source_text_hash
|
||
if 'content_hash' in current_columns and 'source_text_hash' not in current_columns:
|
||
print("\n[3/6] 重新命名 content_hash → source_text_hash...")
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
CHANGE COLUMN content_hash source_text_hash VARCHAR(64) NOT NULL COMMENT '來源文字hash'
|
||
'''))
|
||
db.session.commit()
|
||
print(" ✓ 已重新命名")
|
||
else:
|
||
print("\n[3/6] 跳過(已經是 source_text_hash)")
|
||
|
||
# 4. 重新命名欄位:source_lang → source_language
|
||
if 'source_lang' in current_columns and 'source_language' not in current_columns:
|
||
print("\n[4/6] 重新命名 source_lang → source_language...")
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
CHANGE COLUMN source_lang source_language VARCHAR(50) NOT NULL COMMENT '來源語言'
|
||
'''))
|
||
db.session.commit()
|
||
print(" ✓ 已重新命名")
|
||
else:
|
||
print("\n[4/6] 跳過(已經是 source_language)")
|
||
|
||
# 5. 重新命名欄位:target_lang → target_language
|
||
if 'target_lang' in current_columns and 'target_language' not in current_columns:
|
||
print("\n[5/6] 重新命名 target_lang → target_language...")
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
CHANGE COLUMN target_lang target_language VARCHAR(50) NOT NULL COMMENT '目標語言'
|
||
'''))
|
||
db.session.commit()
|
||
print(" ✓ 已重新命名")
|
||
else:
|
||
print("\n[5/6] 跳過(已經是 target_language)")
|
||
|
||
# 6. 刪除不需要的欄位
|
||
print("\n[6/6] 清理多餘欄位...")
|
||
|
||
# 檢查並刪除 quality_score
|
||
if 'quality_score' in current_columns:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
DROP COLUMN quality_score
|
||
'''))
|
||
print(" ✓ 已刪除 quality_score")
|
||
|
||
# 檢查並刪除 hit_count
|
||
if 'hit_count' in current_columns:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
DROP COLUMN hit_count
|
||
'''))
|
||
print(" ✓ 已刪除 hit_count")
|
||
|
||
# 檢查並刪除 last_used_at
|
||
if 'last_used_at' in current_columns:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
DROP COLUMN last_used_at
|
||
'''))
|
||
print(" ✓ 已刪除 last_used_at")
|
||
|
||
db.session.commit()
|
||
|
||
# 7. 重建索引和約束
|
||
print("\n[7/7] 重建索引和約束...")
|
||
|
||
# 先刪除舊的唯一約束(如果存在)
|
||
try:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
DROP INDEX idx_content_hash
|
||
'''))
|
||
print(" ✓ 已刪除舊索引 idx_content_hash")
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
DROP INDEX idx_source_lang_target_lang
|
||
'''))
|
||
print(" ✓ 已刪除舊索引 idx_source_lang_target_lang")
|
||
except:
|
||
pass
|
||
|
||
# 建立新的唯一約束
|
||
try:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
ADD UNIQUE KEY uk_cache (source_text_hash, source_language, target_language)
|
||
'''))
|
||
print(" ✓ 已建立唯一約束 uk_cache")
|
||
except Exception as e:
|
||
if 'Duplicate' not in str(e):
|
||
print(f" ⚠ 約束建立警告: {str(e)}")
|
||
|
||
# 建立語言索引
|
||
try:
|
||
db.session.execute(text('''
|
||
ALTER TABLE dt_translation_cache
|
||
ADD INDEX idx_languages (source_language, target_language)
|
||
'''))
|
||
print(" ✓ 已建立索引 idx_languages")
|
||
except Exception as e:
|
||
if 'Duplicate' not in str(e):
|
||
print(f" ⚠ 索引建立警告: {str(e)}")
|
||
|
||
db.session.commit()
|
||
|
||
# 驗證最終結構
|
||
print("\n" + "=" * 60)
|
||
print("驗證最終資料表結構")
|
||
print("=" * 60)
|
||
|
||
result = db.session.execute(text('SHOW COLUMNS FROM dt_translation_cache'))
|
||
final_columns = list(result)
|
||
|
||
print(f"\n最終欄位列表 (共 {len(final_columns)} 個):")
|
||
for col in final_columns:
|
||
print(f" - {col[0]:30} {col[1]:30} NULL={col[2]}")
|
||
|
||
# 顯示索引
|
||
print("\n索引:")
|
||
result = db.session.execute(text('SHOW INDEX FROM dt_translation_cache'))
|
||
for idx in result:
|
||
print(f" - {idx[2]:30} -> {idx[4]}")
|
||
|
||
print("\n" + "=" * 60)
|
||
print("✅ Migration 執行完成!")
|
||
print("=" * 60)
|
||
|
||
except Exception as e:
|
||
db.session.rollback()
|
||
print(f"\n❌ Migration 失敗: {str(e)}")
|
||
print("\n可以使用備份表還原資料:")
|
||
print(" DROP TABLE dt_translation_cache;")
|
||
print(" CREATE TABLE dt_translation_cache AS SELECT * FROM dt_translation_cache_backup_20251001;")
|
||
raise
|
||
|
||
|
||
if __name__ == '__main__':
|
||
run_migration()
|