diff --git a/api/alembic/versions/0005_cleanup_cross_chapter_story_links.py b/api/alembic/versions/0005_cleanup_cross_chapter_story_links.py index 0a06c5a..cf7d7b5 100644 --- a/api/alembic/versions/0005_cleanup_cross_chapter_story_links.py +++ b/api/alembic/versions/0005_cleanup_cross_chapter_story_links.py @@ -9,6 +9,7 @@ Revises: 0004_memory_embedding_1024 from typing import Sequence, Union import sqlalchemy as sa +from sqlalchemy.dialects import postgresql from alembic import op @@ -18,7 +19,42 @@ branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None +def _has_column(table: str, column: str) -> bool: + bind = op.get_bind() + return any(c["name"] == column for c in sa.inspect(bind).get_columns(table)) + + +def _ensure_chapter_materialization_columns() -> None: + """Keep older/squashed staging schemas compatible before this data cleanup.""" + if not _has_column("chapters", "markdown_compose_dirty"): + op.add_column( + "chapters", + sa.Column( + "markdown_compose_dirty", + sa.Boolean(), + nullable=False, + server_default=sa.text("false"), + ), + ) + if not _has_column("chapters", "markdown_composed_at"): + op.add_column( + "chapters", + sa.Column("markdown_composed_at", sa.DateTime(timezone=True), nullable=True), + ) + if not _has_column("chapters", "reading_segments_json"): + op.add_column( + "chapters", + sa.Column( + "reading_segments_json", + postgresql.JSON(astext_type=sa.Text()), + nullable=True, + ), + ) + + def upgrade() -> None: + _ensure_chapter_materialization_columns() + # 先标脏,再删链接(子查询在 DELETE 后不可用) op.execute( sa.text(