Files
Haocode/tests/check_db_migration.py
T
sorrow404null a7412824e0 chore: import original project baseline
Import the pre-repair source tree as the history baseline.
Runtime data (data/), virtualenvs, bytecode caches and logs are
gitignored so local secrets and user state stay out of the repo.
2026-09-17 16:40:01 +08:00

78 lines
3.0 KiB
Python

# -*- coding: utf-8 -*-
"""用「备份 ZIP 里的真实旧库」验证:迁移新列后旧数据必须 100% 原样保留(只读对比)。
用法: python tests/check_db_migration.py <backup.zip>
"""
import os
import sys
import json
import shutil
import sqlite3
import tempfile
import zipfile
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
ZIP = sys.argv[1] if len(sys.argv) > 1 else r"D:/haocode_backup_20260916_1102.zip"
OUT = os.path.join(tempfile.gettempdir(), "haocode_from_backup.db")
if os.path.exists(OUT):
os.remove(OUT)
with zipfile.ZipFile(ZIP) as z:
name = [n for n in z.namelist()
if os.path.basename(n) == "chat_history.db"][0]
with z.open(name) as src, open(OUT, "wb") as dst:
shutil.copyfileobj(src, dst)
print("从备份取出:", name, os.path.getsize(OUT), "bytes")
def fp(path):
c = sqlite3.connect(path)
c.row_factory = sqlite3.Row
cols = [r[1] for r in c.execute("PRAGMA table_info(messages)")]
d = {
"messages_rows": c.execute("SELECT COUNT(*) FROM messages").fetchone()[0],
"sessions_rows": c.execute("SELECT COUNT(*) FROM sessions").fetchone()[0],
"msg_sum": list(c.execute(
"SELECT COUNT(*), SUM(LENGTH(COALESCE(content,''))), "
"SUM(LENGTH(COALESCE(timeline,''))) FROM messages").fetchone()[:]),
"parents": [tuple(r) for r in c.execute(
"SELECT id, parent_id FROM messages ORDER BY id")],
"leaves": [tuple(r) for r in c.execute(
"SELECT id, current_leaf_msg_id FROM sessions ORDER BY id")],
"branches": sorted((r["parent_id"], r["n"]) for r in c.execute(
"SELECT parent_id, COUNT(*) n FROM messages "
"WHERE parent_id IS NOT NULL GROUP BY parent_id HAVING n>1")),
"roles": sorted((r["role"], r["n"]) for r in c.execute(
"SELECT role, COUNT(*) n FROM messages GROUP BY role")),
"has_new_cols": all(x in cols for x in ("stop_reason", "error_message")),
}
c.close()
return d
before = fp(OUT)
print("备份库(迁移前): 消息=%d 会话=%d 分支点=%d 含新列=%s" % (
before["messages_rows"], before["sessions_rows"],
len(before["branches"]), before["has_new_cols"]))
import core.db_manager as _dbm # noqa: E402
_dbm._DEFAULT_DB = OUT
d = _dbm.DBManager(db_path=OUT) # ← 触发迁移
after = fp(OUT)
print("迁移后 : 消息=%d 会话=%d 分支点=%d 含新列=%s" % (
after["messages_rows"], after["sessions_rows"],
len(after["branches"]), after["has_new_cols"]))
print()
keys = ("messages_rows", "sessions_rows", "msg_sum", "parents",
"leaves", "branches", "roles")
for k in keys:
print((" OK " if before[k] == after[k] else " DIFF ") + "%-14s" % k)
allok = all(before[k] == after[k] for k in keys)
print()
print("每个会话叶子:", [(r[0][:16], (r[1] or "")[:16]) for r in after["leaves"][:4]], "...")
print(">>> 结论:", "✅ 旧库数据 100% 原样保留(只多两个空列)"
if allok else "❌ 有改动!")
os.remove(OUT)
sys.exit(0 if allok else 1)