Files
opensquilla--opensquilla/migrations/V002__scheduler_session_fields.py
2026-07-13 13:12:33 +08:00

68 lines
2.1 KiB
Python

"""V002 - scheduler session-forward fields (wrong-database no-op).
Adds ``origin_session_key`` to ``scheduler_jobs`` so the scheduler can
carry the scheduling session identity through to delivery-time fan-out.
``scheduler_jobs`` lives in ``scheduler.db`` (``JobStore`` opened from
``gateway/boot.py``), NOT in ``sessions.db`` — and ``apply_pending`` only
ever runs against ``sessions.db``. On real split-database deployments the
table is therefore absent from the migration connection and this step
no-ops, recorded in the sessions.db ledger without touching scheduler
data. The real in-place upgrade is ``JobStore._migrate``'s connect-time
ADD COLUMN pass (``scheduler/persistence.py``).
The guards below keep the step harmless and idempotent on databases
where ``scheduler_jobs`` does share a file with the session store (e.g.
ad-hoc test setups). Rollback drops the column (SQLite 3.35+ supports
DROP COLUMN natively).
"""
from __future__ import annotations
from yoyo import step
__depends__: set[str] = {"V001__initial_schema"}
TABLE = "scheduler_jobs"
COLUMN = "origin_session_key"
COLUMN_DDL = f"{COLUMN} TEXT NOT NULL DEFAULT ''"
def _table_exists(conn, table: str) -> bool:
cur = conn.cursor()
cur.execute(
"SELECT 1 FROM sqlite_master WHERE type='table' AND name=?",
(table,),
)
return cur.fetchone() is not None
def _has_column(conn, table: str, column: str) -> bool:
cur = conn.cursor()
cur.execute(f"PRAGMA table_info({table})")
return any(row[1] == column for row in cur.fetchall())
def apply_step(conn) -> None:
if not _table_exists(conn, TABLE):
# Fresh DB - JobStore.open() creates the table with the in-process
# ADD COLUMN loop handling origin_session_key itself.
return
if _has_column(conn, TABLE, COLUMN):
return
cur = conn.cursor()
cur.execute(f"ALTER TABLE {TABLE} ADD COLUMN {COLUMN_DDL}")
def rollback_step(conn) -> None:
if not _table_exists(conn, TABLE):
return
if not _has_column(conn, TABLE, COLUMN):
return
cur = conn.cursor()
cur.execute(f"ALTER TABLE {TABLE} DROP COLUMN {COLUMN}")
steps = [step(apply_step, rollback_step)]