"""asset_software_catalog — add long-text ``description`` column. The catalog already has ``remark`` (备注) and ``license_info`` (License 信息), but both are short-form TEXT fields the admin uses for one-liners. Some software needs a genuinely long write-up — onboarding guide, what it's for, internal policy, links — that doesn't belong in 备注. This adds a dedicated 「详细介绍」 field. MEDIUMTEXT (16MB) rather than TEXT (64KB): the field is meant to hold long content, and a worst-case 20K-char utf8mb4 value (the Pydantic cap) is up to 80KB, which overflows TEXT. MEDIUMTEXT removes the worry entirely. Idempotent — re-run is a no-op via INFORMATION_SCHEMA check. Revision ID: 328 Revises: 327 """ # ruff: noqa: I001 from __future__ import annotations import sqlalchemy as sa from sqlalchemy.dialects.mysql import MEDIUMTEXT from alembic import op revision = "328" down_revision = "327" branch_labels = None depends_on = None TABLE = "asset_software_catalog" COLUMN = "description" def _column_exists(bind, table: str, column: str) -> bool: rows = bind.execute( sa.text( "SELECT COUNT(*) FROM information_schema.COLUMNS " "WHERE TABLE_SCHEMA = DATABASE() " "AND TABLE_NAME = :t AND COLUMN_NAME = :c" ), {"t": table, "c": column}, ).scalar() return bool(rows) def upgrade() -> None: bind = op.get_bind() if _column_exists(bind, TABLE, COLUMN): return op.add_column(TABLE, sa.Column(COLUMN, MEDIUMTEXT(), nullable=True)) def downgrade() -> None: bind = op.get_bind() if not _column_exists(bind, TABLE, COLUMN): return op.drop_column(TABLE, COLUMN)