From 5e0e39bfc3344a4eb1aaf1c81e1398f246237b20 Mon Sep 17 00:00:00 2001 From: passthem Date: Sat, 7 Mar 2026 13:52:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=9F=BA=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E8=A1=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- konabot/common/permsys/migrates/__init__.py | 81 +++++++++++++++++++ .../migrates/check_migrate_version_exists.sql | 7 ++ .../migrates/create_migrate_version_table.sql | 3 + .../permsys/migrates/get_migrate_version.sql | 4 + .../migrates/md1_remove_permsys_table.sql | 2 + .../migrates/mu1_create_permsys_table.sql | 25 ++++++ .../migrates/update_migrate_version.sql | 2 + tests/test_permsys.py | 32 ++++++++ 8 files changed, 156 insertions(+) create mode 100644 konabot/common/permsys/migrates/__init__.py create mode 100644 konabot/common/permsys/migrates/check_migrate_version_exists.sql create mode 100644 konabot/common/permsys/migrates/create_migrate_version_table.sql create mode 100644 konabot/common/permsys/migrates/get_migrate_version.sql create mode 100644 konabot/common/permsys/migrates/md1_remove_permsys_table.sql create mode 100644 konabot/common/permsys/migrates/mu1_create_permsys_table.sql create mode 100644 konabot/common/permsys/migrates/update_migrate_version.sql create mode 100644 tests/test_permsys.py diff --git a/konabot/common/permsys/migrates/__init__.py b/konabot/common/permsys/migrates/__init__.py new file mode 100644 index 0000000..f148618 --- /dev/null +++ b/konabot/common/permsys/migrates/__init__.py @@ -0,0 +1,81 @@ +from dataclasses import dataclass +from pathlib import Path + +import aiosqlite +from loguru import logger + +from konabot.common.database import DatabaseManager +from konabot.common.path import DATA_PATH + + +PATH_THISFOLDER = Path(__file__).parent + +SQL_CHECK_EXISTS = (PATH_THISFOLDER / "./check_migrate_version_exists.sql").read_text() +SQL_CREATE_TABLE = (PATH_THISFOLDER / "./create_migrate_version_table.sql").read_text() +SQL_GET_MIGRATE_VERSION = (PATH_THISFOLDER / "get_migrate_version.sql").read_text() +SQL_UPDATE_VERSION = (PATH_THISFOLDER / "./update_migrate_version.sql").read_text() + +db = DatabaseManager(DATA_PATH / "perm.sqlite3") + + +@dataclass +class Migration: + upgrade: str | Path + downgrade: str | Path + + def get_upgrade_script(self) -> str: + if isinstance(self.upgrade, Path): + return self.upgrade.read_text() + return self.upgrade + + def get_downgrade_script(self) -> str: + if isinstance(self.upgrade, Path): + return self.upgrade.read_text() + return self.upgrade + + +migrations = [ + Migration( + PATH_THISFOLDER / "./mu1_create_permsys_table.sql", + PATH_THISFOLDER / "./md1_remove_permsys_table.sql", + ), +] + + +TARGET_VERSION = len(migrations) + + +async def get_current_version(conn: aiosqlite.Connection) -> int: + cursor = await conn.execute(SQL_CHECK_EXISTS) + count = await cursor.fetchone() + assert count is not None + if count[0] < 1: + logger.info("权限系统数据表不存在,现在创建表") + await conn.executescript(SQL_CREATE_TABLE) + await conn.commit() + return -1 + cursor = await conn.execute(SQL_GET_MIGRATE_VERSION) + row = await cursor.fetchone() + if row is None: + return -1 + return row[0] + + +async def execute_migration( + conn: aiosqlite.Connection, + version: int = TARGET_VERSION, + migrations: list[Migration] = migrations, +): + now_version = await get_current_version(conn) + while now_version < version: + migration = migrations[now_version] + await conn.executescript(migration.get_upgrade_script()) + now_version += 1 + await conn.execute(SQL_UPDATE_VERSION, (now_version,)) + await conn.commit() + while now_version > version: + migration = migrations[now_version - 1] + await conn.executescript(migration.get_downgrade_script()) + now_version -= 1 + await conn.execute(SQL_UPDATE_VERSION, (now_version,)) + await conn.commit() diff --git a/konabot/common/permsys/migrates/check_migrate_version_exists.sql b/konabot/common/permsys/migrates/check_migrate_version_exists.sql new file mode 100644 index 0000000..56e350c --- /dev/null +++ b/konabot/common/permsys/migrates/check_migrate_version_exists.sql @@ -0,0 +1,7 @@ +SELECT + COUNT(*) +FROM + sqlite_master +WHERE + type = 'table' + AND name = 'migrate_version' diff --git a/konabot/common/permsys/migrates/create_migrate_version_table.sql b/konabot/common/permsys/migrates/create_migrate_version_table.sql new file mode 100644 index 0000000..0d46cca --- /dev/null +++ b/konabot/common/permsys/migrates/create_migrate_version_table.sql @@ -0,0 +1,3 @@ +CREATE TABLE migrate_version(version INT PRIMARY KEY); +INSERT INTO migrate_version(version) +VALUES(0); diff --git a/konabot/common/permsys/migrates/get_migrate_version.sql b/konabot/common/permsys/migrates/get_migrate_version.sql new file mode 100644 index 0000000..7ba0745 --- /dev/null +++ b/konabot/common/permsys/migrates/get_migrate_version.sql @@ -0,0 +1,4 @@ +SELECT + version +FROM + migrate_version; diff --git a/konabot/common/permsys/migrates/md1_remove_permsys_table.sql b/konabot/common/permsys/migrates/md1_remove_permsys_table.sql new file mode 100644 index 0000000..3292759 --- /dev/null +++ b/konabot/common/permsys/migrates/md1_remove_permsys_table.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS perm_entity; +DROP TABLE IF EXISTS perm_info; diff --git a/konabot/common/permsys/migrates/mu1_create_permsys_table.sql b/konabot/common/permsys/migrates/mu1_create_permsys_table.sql new file mode 100644 index 0000000..98793b8 --- /dev/null +++ b/konabot/common/permsys/migrates/mu1_create_permsys_table.sql @@ -0,0 +1,25 @@ +CREATE TABLE perm_entity( + id INTEGER PRIMARY KEY AUTOINCREMENT, + platform TEXT NOT NULL, + entity_type TEXT NOT NULL, + external_id TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE perm_info( + entity_id INTEGER NOT NULL, + config_key TEXT NOT NULL, + value BOOLEAN NOT NULL, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +CREATE TRIGGER perm_entity_update AFTER UPDATE +ON perm_entity BEGIN + UPDATE perm_entity SET updated_at=CURRENT_TIMESTAMP WHERE id=old.id; +END; +CREATE TRIGGER perm_info_update AFTER UPDATE +ON perm_info BEGIN + UPDATE perm_info SET updated_at=CURRENT_TIMESTAMP WHERE id=old.id; +END; + diff --git a/konabot/common/permsys/migrates/update_migrate_version.sql b/konabot/common/permsys/migrates/update_migrate_version.sql new file mode 100644 index 0000000..589aa28 --- /dev/null +++ b/konabot/common/permsys/migrates/update_migrate_version.sql @@ -0,0 +1,2 @@ +UPDATE migrate_version +SET version = ?; diff --git a/tests/test_permsys.py b/tests/test_permsys.py new file mode 100644 index 0000000..1ffeefb --- /dev/null +++ b/tests/test_permsys.py @@ -0,0 +1,32 @@ +from contextlib import asynccontextmanager +from pathlib import Path +from tempfile import TemporaryDirectory +import pytest + +from konabot.common.database import DatabaseManager +from konabot.common.permsys.migrates import execute_migration, get_current_version + + +@asynccontextmanager +async def tempdb(): + with TemporaryDirectory() as _tempdir: + tempdir = Path(_tempdir) + db = DatabaseManager(tempdir / "perm.sqlite3") + yield db + await db.close_all_connections() + + +@pytest.mark.asyncio +async def test_get_db_version(): + async with tempdb() as db: + async with db.get_conn() as conn: + v = await get_current_version(conn) + assert v == -1 + v = await get_current_version(conn) + assert v == 0 + await execute_migration(conn, version=1) + v = await get_current_version(conn) + assert v == 1 + await execute_migration(conn, version=0) + v = await get_current_version(conn) + assert v == 0