做安装包版本
This commit is contained in:
Binary file not shown.
+113
-36
@@ -4,6 +4,8 @@ import shutil
|
||||
|
||||
# 数据库放到 Windows 常见的 APPDATA 目录(避免写在项目目录)
|
||||
APP_NAME = "CleanDesktopOrganizer"
|
||||
_SCHEMA_VERSION_KEY = "schema_version"
|
||||
LATEST_SCHEMA_VERSION = 1
|
||||
|
||||
_PROJECT_DB_PATH = os.path.join(
|
||||
os.path.dirname(os.path.dirname(__file__)), "data.db"
|
||||
@@ -37,52 +39,127 @@ def get_conn():
|
||||
_ensure_db_dir()
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
try:
|
||||
conn.execute("PRAGMA foreign_keys=ON")
|
||||
except Exception:
|
||||
pass
|
||||
return conn
|
||||
|
||||
|
||||
def _get_schema_version(conn: sqlite3.Connection) -> int:
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT value FROM settings WHERE key=?",
|
||||
(_SCHEMA_VERSION_KEY,),
|
||||
).fetchone()
|
||||
if not row:
|
||||
return 0
|
||||
return int(str(row[0]).strip() or "0")
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def _set_schema_version(conn: sqlite3.Connection, v: int):
|
||||
conn.execute(
|
||||
"INSERT INTO settings (key, value) VALUES (?,?) "
|
||||
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
|
||||
(_SCHEMA_VERSION_KEY, str(int(v))),
|
||||
)
|
||||
|
||||
|
||||
def _table_has_column(conn: sqlite3.Connection, table: str, col: str) -> bool:
|
||||
try:
|
||||
rows = conn.execute(f"PRAGMA table_info({table})").fetchall()
|
||||
return any((r[1] if isinstance(r, (tuple, list)) else r["name"]) == col for r in rows)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _apply_migrations(conn: sqlite3.Connection):
|
||||
"""
|
||||
版本化迁移(schema migration):
|
||||
- 允许从任意旧版本升级到最新
|
||||
- 每一步尽量幂等,并在事务中执行
|
||||
"""
|
||||
|
||||
def m1():
|
||||
# 基础表
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS groups (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
position INTEGER DEFAULT 0,
|
||||
folder_path TEXT DEFAULT ''
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
group_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
icon_path TEXT,
|
||||
position INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
|
||||
)
|
||||
"""
|
||||
)
|
||||
# 兼容更老的库:补字段
|
||||
if not _table_has_column(conn, "groups", "folder_path"):
|
||||
conn.execute("ALTER TABLE groups ADD COLUMN folder_path TEXT DEFAULT ''")
|
||||
|
||||
migrations = {
|
||||
1: m1,
|
||||
}
|
||||
|
||||
cur = _get_schema_version(conn)
|
||||
# 未设置版本但已有表:视为 0,走迁移补齐并写入版本号
|
||||
while cur < LATEST_SCHEMA_VERSION:
|
||||
nxt = cur + 1
|
||||
fn = migrations.get(nxt)
|
||||
if fn is None:
|
||||
raise RuntimeError(f"missing migration for version {nxt}")
|
||||
with conn:
|
||||
fn()
|
||||
_set_schema_version(conn, nxt)
|
||||
cur = nxt
|
||||
|
||||
|
||||
def init_db():
|
||||
_migrate_old_db_if_needed()
|
||||
conn = get_conn()
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS groups (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
position INTEGER DEFAULT 0,
|
||||
folder_path TEXT DEFAULT ''
|
||||
# 先确保 settings 表存在,才能读写 schema_version
|
||||
with conn:
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
""")
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
group_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
icon_path TEXT,
|
||||
position INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
|
||||
)
|
||||
""")
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
# 迁移:旧库没有 folder_path 字段时自动添加
|
||||
try:
|
||||
c.execute("ALTER TABLE groups ADD COLUMN folder_path TEXT DEFAULT ''")
|
||||
conn.commit()
|
||||
except Exception:
|
||||
pass # 字段已存在则忽略
|
||||
_apply_migrations(conn)
|
||||
|
||||
# 默认分组
|
||||
c.execute("SELECT COUNT(*) FROM groups")
|
||||
if c.fetchone()[0] == 0:
|
||||
c.execute("INSERT INTO groups (name, position) VALUES ('常用程序', 0)")
|
||||
conn.commit()
|
||||
# 默认分组(数据迁移/初始化)
|
||||
with conn:
|
||||
row = conn.execute("SELECT COUNT(*) FROM groups").fetchone()
|
||||
cnt = int(row[0] if row else 0)
|
||||
if cnt == 0:
|
||||
conn.execute("INSERT INTO groups (name, position) VALUES ('常用程序', 0)")
|
||||
conn.close()
|
||||
|
||||
# 非结构类迁移(数据清洗/一次性转换)
|
||||
_migrate_item_shortcut_paths_to_targets()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user