"""正文提取错误落库:doc_document 增加 content_extract_error 列。 Revision ID: 0019_content_extract_error Revises: 0018_sub_plan_binding Create Date: 2026-08-27 变更要点: 1. doc_document 增加 content_extract_error VARCHAR(512) NULL, 记录正文提取失败的脱敏原因(异常类型+首行信息,去除绝对路径), 供管理员在"编辑"界面排障;成功/空文本/不支持时为 NULL; 2. 存量行保持 NULL,无需回填(可经"重新解析"接口按需重提); 3. 升级为幂等:列已存在时跳过;降级仅在有失败记录时拒绝有损删除。 """ from __future__ import annotations from collections.abc import Sequence from alembic import op import sqlalchemy as sa revision: str = "0019_content_extract_error" down_revision: str | None = "0018_sub_plan_binding" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None _TABLE = "doc_document" _COLUMN = "content_extract_error" def _existing_columns() -> set[str]: inspector = sa.inspect(op.get_bind()) return {column["name"] for column in inspector.get_columns(_TABLE)} def upgrade() -> None: if _COLUMN in _existing_columns(): return op.add_column( _TABLE, sa.Column(_COLUMN, sa.String(512), nullable=True), ) def downgrade() -> None: if _COLUMN not in _existing_columns(): return bind = op.get_bind() error_rows = bind.scalar( sa.text( f"SELECT COUNT(*) FROM {_TABLE} WHERE {_COLUMN} IS NOT NULL" ) ) if error_rows: raise RuntimeError( "0019已产生提取失败记录,拒绝有损降级;请先备份并按数据治理流程处理" ) op.drop_column(_TABLE, _COLUMN)