166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
数据库迁移脚本:添加 revision_count, is_latest, original_entry_id 字段
|
|
"""
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# 加载 .env 文件
|
|
env_file = Path(__file__).parent.parent / ".env"
|
|
if env_file.exists():
|
|
with open(env_file) as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line and not line.startswith("#"):
|
|
key, value = line.split("=", 1)
|
|
os.environ[key.strip()] = value.strip()
|
|
|
|
from psycopg import connect
|
|
|
|
def run_migration():
|
|
try:
|
|
# 从环境变量获取数据库连接信息
|
|
db_password = os.getenv("DB_PASSWORD")
|
|
print(f"📛 连接数据库: {os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}")
|
|
print(f"👤 用户: {os.getenv('DB_USER')}")
|
|
|
|
# 尝试用 njts_app 用户连接,不行的话尝试 postgres
|
|
users_to_try = [
|
|
{
|
|
"user": os.getenv("DB_USER"),
|
|
"password": db_password
|
|
},
|
|
{
|
|
"user": "postgres",
|
|
"password": "" # 空密码或尝试无密码
|
|
}
|
|
]
|
|
|
|
conn = None
|
|
last_error = None
|
|
|
|
for cred in users_to_try:
|
|
try:
|
|
print(f"尝试连接用户: {cred['user']}")
|
|
conn = connect(
|
|
host=os.getenv("DB_HOST"),
|
|
port=int(os.getenv("DB_PORT")),
|
|
dbname=os.getenv("DB_NAME"),
|
|
user=cred["user"],
|
|
password=cred["password"] if cred["password"] else None,
|
|
)
|
|
print(f"✓ 成功连接为用户: {cred['user']}")
|
|
break
|
|
except Exception as e:
|
|
last_error = e
|
|
print(f"✗ 连接失败: {e}")
|
|
continue
|
|
|
|
if not conn:
|
|
raise Exception(f"无法连接到数据库。最后错误: {last_error}")
|
|
|
|
with conn.cursor() as cur:
|
|
# 首先检查字段是否存在
|
|
print("🔄 检查字段是否存在...")
|
|
cur.execute("""
|
|
SELECT column_name FROM information_schema.columns
|
|
WHERE table_name = 'journal_entries'
|
|
AND column_name IN ('is_latest', 'revision_count', 'original_entry_id')
|
|
""")
|
|
existing_columns = {row[0] for row in cur.fetchall()}
|
|
print(f"已存在的字段: {existing_columns}")
|
|
|
|
# 添加 is_latest 字段
|
|
if 'is_latest' not in existing_columns:
|
|
print("🔄 添加 is_latest 字段...")
|
|
try:
|
|
cur.execute("""
|
|
ALTER TABLE journal_entries
|
|
ADD COLUMN is_latest BOOLEAN DEFAULT true;
|
|
""")
|
|
print("✓ is_latest 字段已添加")
|
|
except Exception as e:
|
|
print(f"✗ 添加失败: {e}")
|
|
else:
|
|
print("✓ is_latest 字段已存在")
|
|
print("✓ is_latest 字段处理完成")
|
|
|
|
# 添加 revision_count 字段
|
|
print("🔄 检查 revision_count 字段...")
|
|
cur.execute("""
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'journal_entries' AND column_name = 'revision_count') THEN
|
|
ALTER TABLE journal_entries ADD COLUMN revision_count INTEGER DEFAULT 1;
|
|
RAISE NOTICE '字段 revision_count 已添加';
|
|
ELSE
|
|
RAISE NOTICE '字段 revision_count 已存在';
|
|
END IF;
|
|
END $$;
|
|
""")
|
|
print("✓ revision_count 字段处理完成")
|
|
|
|
# 添加 original_entry_id 字段
|
|
print("🔄 检查 original_entry_id 字段...")
|
|
cur.execute("""
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'journal_entries' AND column_name = 'original_entry_id') THEN
|
|
ALTER TABLE journal_entries ADD COLUMN original_entry_id INTEGER;
|
|
ALTER TABLE journal_entries ADD CONSTRAINT fk_original_entry_id
|
|
FOREIGN KEY (original_entry_id) REFERENCES journal_entries(journal_entry_id) ON DELETE CASCADE;
|
|
RAISE NOTICE '字段 original_entry_id 已添加';
|
|
ELSE
|
|
RAISE NOTICE '字段 original_entry_id 已存在';
|
|
END IF;
|
|
END $$;
|
|
""")
|
|
print("✓ original_entry_id 字段处理完成")
|
|
|
|
# 创建索引
|
|
print("🔄 创建索引...")
|
|
cur.execute("""
|
|
CREATE INDEX IF NOT EXISTS idx_journal_entries_is_latest
|
|
ON journal_entries(is_latest, entry_date);
|
|
""")
|
|
print("✓ idx_journal_entries_is_latest 索引已创建")
|
|
|
|
cur.execute("""
|
|
CREATE INDEX IF NOT EXISTS idx_journal_entries_original_entry_id
|
|
ON journal_entries(original_entry_id);
|
|
""")
|
|
print("✓ idx_journal_entries_original_entry_id 索引已创建")
|
|
|
|
# 验证字段
|
|
print("🔄 验证字段...")
|
|
cur.execute("""
|
|
SELECT column_name, data_type, is_nullable
|
|
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()
|
|
print("\n📋 数据库字段信息:")
|
|
for row in rows:
|
|
print(f" - {row[0]}: {row[1]} (nullable: {row[2]})")
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
print("\n✅ 迁移完成!")
|
|
return 0
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ 迁移失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(run_migration())
|