mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
refactor: isolate passkey queries
This commit is contained in:
+2
-3
@@ -13,8 +13,8 @@
|
||||
"runtime_to_db": [],
|
||||
"workflow_to_db": []
|
||||
},
|
||||
"edge_count": 6464,
|
||||
"edge_sha256": "256ae6f9cd8950b0fe2743e81300551877eb595bda37b8ce114f439b33496af9",
|
||||
"edge_count": 6463,
|
||||
"edge_sha256": "086c14fef27199ae6f19fbe5e6a07c348cd1dc8a406ab3129a341647fd90a28f",
|
||||
"edges": [
|
||||
"app -> app.runtime",
|
||||
"app -> app.runtime.compat",
|
||||
@@ -3629,7 +3629,6 @@
|
||||
"app.db.oper.passkey -> app.db.base",
|
||||
"app.db.oper.passkey -> app.db.models",
|
||||
"app.db.oper.passkey -> app.db.models.passkey",
|
||||
"app.db.oper.passkey -> app.db.uow",
|
||||
"app.db.oper.plugindata -> app.db",
|
||||
"app.db.oper.plugindata -> app.db.base",
|
||||
"app.db.oper.plugindata -> app.db.models",
|
||||
|
||||
+3
-23
@@ -1,33 +1,13 @@
|
||||
{
|
||||
"model_decorators": {
|
||||
"by_kind": {
|
||||
"async_db_query": 6,
|
||||
"async_db_query": 3,
|
||||
"async_db_update": 0,
|
||||
"db_query": 3,
|
||||
"db_query": 2,
|
||||
"db_update": 0
|
||||
},
|
||||
"count": 9,
|
||||
"count": 5,
|
||||
"methods": [
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/passkey.py",
|
||||
"method": "PassKey.async_get_by_credential_id"
|
||||
},
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/passkey.py",
|
||||
"method": "PassKey.async_get_by_id"
|
||||
},
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/passkey.py",
|
||||
"method": "PassKey.async_get_by_user_id"
|
||||
},
|
||||
{
|
||||
"decorator": "db_query",
|
||||
"file": "app/db/models/passkey.py",
|
||||
"method": "PassKey.get_by_id"
|
||||
},
|
||||
{
|
||||
"decorator": "async_db_query",
|
||||
"file": "app/db/models/subscribehistory.py",
|
||||
|
||||
@@ -126,8 +126,8 @@ def test_transaction_debt_baseline_is_a_model_and_oper_ratchet() -> None:
|
||||
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
|
||||
|
||||
assert baseline["schema_version"] == 1
|
||||
assert baseline["model_decorators"]["count"] == 9
|
||||
assert sum(baseline["model_decorators"]["by_kind"].values()) == 9
|
||||
assert baseline["model_decorators"]["count"] == 5
|
||||
assert sum(baseline["model_decorators"]["by_kind"].values()) == 5
|
||||
assert baseline["model_decorators"]["by_kind"]["db_update"] == 0
|
||||
assert baseline["model_decorators"]["by_kind"]["async_db_update"] == 0
|
||||
assert baseline["model_transaction_calls"] == {"count": 0, "calls": []}
|
||||
|
||||
@@ -266,12 +266,16 @@ def test_passkey_oper_queries_use_explicit_session(db, monkeypatch):
|
||||
"""PassKeyOper 的宿主查询使用调用方 Session,不创建兼容事务。"""
|
||||
db.add(_passkey(9002, "cred-oper"), _passkey(9002, "cred-oper-inactive", is_active=False))
|
||||
monkeypatch.setattr(
|
||||
"app.db.oper.passkey.run_sync_transaction",
|
||||
"app.db.base.run_sync_transaction",
|
||||
lambda _query: pytest.fail("显式 Session 查询不应创建兼容事务"),
|
||||
)
|
||||
|
||||
oper = PassKeyOper(db.session)
|
||||
|
||||
assert {item.credential_id for item in oper.list()} == {
|
||||
"cred-oper",
|
||||
"cred-oper-inactive",
|
||||
}
|
||||
assert [item.credential_id for item in oper.list_by_user_id(9002)] == ["cred-oper"]
|
||||
assert oper.get_by_credential_id("cred-oper").user_id == 9002
|
||||
assert oper.get_by_credential_id("cred-oper-inactive") is None
|
||||
@@ -302,6 +306,66 @@ def test_passkey_model_sync_queries_keep_no_session_plugin_abi(db, monkeypatch):
|
||||
assert PassKey.get_by_credential_id("cred-legacy").user_id == 9004
|
||||
|
||||
|
||||
def test_passkey_remaining_queries_reuse_explicit_sessions(db, monkeypatch):
|
||||
"""PassKey 其余同步/异步查询必须复用调用方会话。"""
|
||||
key = db.add(_passkey(9008, "cred-explicit"))
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外同步会话")),
|
||||
)
|
||||
assert PassKey.get_by_id(db.session, key.id).credential_id == "cred-explicit"
|
||||
|
||||
async def check() -> None:
|
||||
"""验证三个异步查询都复用显式 AsyncSession。"""
|
||||
async with async_session_scope() as session:
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"async_session_scope",
|
||||
lambda: (_ for _ in ()).throw(AssertionError("不应创建额外异步会话")),
|
||||
)
|
||||
assert [item.credential_id for item in await PassKey.async_get_by_user_id(
|
||||
session,
|
||||
9008,
|
||||
)] == ["cred-explicit"]
|
||||
assert await PassKey.async_get_by_credential_id(
|
||||
session,
|
||||
"cred-explicit",
|
||||
) is not None
|
||||
assert await PassKey.async_get_by_id(session, key.id) is not None
|
||||
|
||||
asyncio.run(check())
|
||||
|
||||
|
||||
def test_passkey_remaining_queries_keep_legacy_keyword_abi(db, monkeypatch):
|
||||
"""旧插件关键字直调 PassKey 其余查询时仍自动补入短会话。"""
|
||||
key = db.add(_passkey(9009, "cred-keyword"))
|
||||
opened_sync = []
|
||||
monkeypatch.setattr(
|
||||
decorators,
|
||||
"ScopedSession",
|
||||
lambda: (opened_sync.append(True) or SessionFactory()),
|
||||
)
|
||||
assert PassKey.get_by_id(passkey_id=key.id) is not None
|
||||
assert opened_sync == [True]
|
||||
|
||||
opened_async = []
|
||||
original_scope = async_session_scope
|
||||
|
||||
def tracked_scope():
|
||||
"""记录旧异步 ABI 创建的兼容会话作用域。"""
|
||||
opened_async.append(True)
|
||||
return original_scope()
|
||||
|
||||
monkeypatch.setattr(decorators, "async_session_scope", tracked_scope)
|
||||
assert asyncio.run(PassKey.async_get_by_user_id(user_id=9009))
|
||||
assert asyncio.run(PassKey.async_get_by_credential_id(
|
||||
credential_id="cred-keyword",
|
||||
)) is not None
|
||||
assert asyncio.run(PassKey.async_get_by_id(passkey_id=key.id)) is not None
|
||||
assert opened_async == [True, True, True]
|
||||
|
||||
|
||||
def test_passkey_get_by_id_ignores_active_flag(db):
|
||||
"""
|
||||
按主键取记录是管理用途,不应过滤停用状态——否则管理端看不到自己刚停用的凭据。
|
||||
|
||||
Reference in New Issue
Block a user