zcbot/db/migrations/versions/20260515_1011_0002_task_dir...

62 lines
2.0 KiB
Python

"""task_dir: ROOT-prefix absolute → relative posix.
Revision ID: 0002
Revises: 0001
Create Date: 2026-05-15
把 `tasks.task_dir` 在 ROOT(本机仓库根)内的绝对路径统一改成相对 ROOT 的 posix 串;
ROOT 外的绝对路径(用户自指定的项目目录)保持原样。
ROOT 从 `core.paths` 读 —— alembic env.py 把项目根注入 sys.path,可正常 import。
存储约定见 DESIGN.md §7.4 / core/paths.py 头部注释。
UPDATE 逻辑:
- 把 task_dir 的 backslash 归一成 `/`(`replace`),与 ROOT 的 posix 串比前缀
- 命中 → 截掉前缀 + 一个分隔符,得到相对 posix
- 没命中 → 不动
downgrade 反向 —— 相对(无盘符 / 不以 `/` 起头)拼回 ROOT。
"""
from typing import Sequence, Union
from alembic import op
from sqlalchemy import text
revision: str = "0002"
down_revision: Union[str, None] = "0001"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def _root_posix() -> str:
from core.paths import ROOT
return str(ROOT).replace("\\", "/")
def upgrade() -> None:
root = _root_posix()
# SUBSTRING from N 是 1-indexed;`<root>/<rel>` 长度 = len(root)+1+len(rel),想取 rel 从 len+2 起
op.execute(
text(
"UPDATE tasks "
"SET task_dir = substring(replace(task_dir, '\\', '/') from :off) "
"WHERE replace(task_dir, '\\', '/') LIKE :prefix"
).bindparams(off=len(root) + 2, prefix=root + "/%")
)
def downgrade() -> None:
root = _root_posix()
# 把"看起来是相对"的行拼回 ROOT 绝对。绝对 = 以 `/` 起头(Linux/posix)或盘符
# `<letter>:` 起头(Windows);LIKE 里 `_` 通配单字符,正好可匹配盘符。
op.execute(
text(
"UPDATE tasks "
"SET task_dir = :prefix || task_dir "
"WHERE task_dir <> '' "
" AND task_dir NOT LIKE '/%' "
" AND task_dir NOT LIKE '_:%'"
).bindparams(prefix=root + "/")
)