Files
border-red-post-nalati/backend/migrations/versions/0002_catalog.py
T

111 lines
4.6 KiB
Python

"""Add source, document, review and audit management."""
import sqlalchemy as sa
from alembic import op
revision = "0002_catalog"
down_revision = "0001_baseline"
branch_labels = None
depends_on = None
def version_columns():
return [
sa.Column("version", sa.Integer(), server_default="1", nullable=False),
sa.Column(
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
),
sa.Column(
"updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
),
sa.Column("is_deleted", sa.Boolean(), server_default=sa.false(), nullable=False),
]
def upgrade():
op.create_table(
"sources",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("name", sa.String(250), nullable=False),
sa.Column("source_url", sa.String(1000)),
sa.Column("notes", sa.Text(), nullable=False),
*version_columns(),
)
op.create_table(
"documents",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("source_id", sa.Integer(), sa.ForeignKey("sources.id"), nullable=False),
sa.Column("title", sa.String(250), nullable=False),
sa.Column("category", sa.String(80), nullable=False),
sa.Column("content", sa.Text(), nullable=False),
sa.Column("collected_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("notes", sa.Text(), nullable=False),
*version_columns(),
)
op.create_index("ix_documents_source_id", "documents", ["source_id"])
op.create_table(
"audit_events",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("entity_type", sa.String(30), nullable=False),
sa.Column("entity_id", sa.Integer(), nullable=False),
sa.Column("action", sa.String(30), nullable=False),
sa.Column("actor", sa.String(100)),
sa.Column("notes", sa.Text(), nullable=False),
sa.Column("snapshot", sa.JSON(), nullable=False),
sa.Column(
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
),
)
op.create_index("ix_audit_events_entity_type", "audit_events", ["entity_type"])
op.create_index("ix_audit_events_entity_id", "audit_events", ["entity_id"])
for column in version_columns():
if column.name != "created_at":
op.add_column("knowledge_items", column)
for name, kind in [
("source_id", sa.Integer()),
("document_id", sa.Integer()),
("collected_at", sa.DateTime(timezone=True)),
("reviewer", sa.String(100)),
("reviewed_at", sa.DateTime(timezone=True)),
("verification_notes", sa.Text()),
]:
op.add_column("knowledge_items", sa.Column(name, kind))
for name, parent in [("source_id", "sources"), ("document_id", "documents")]:
op.create_foreign_key(f"fk_knowledge_{name}", "knowledge_items", parent, [name], ["id"])
op.create_index(f"ix_knowledge_items_{name}", "knowledge_items", [name])
op.create_check_constraint(
"ck_knowledge_verification_status",
"knowledge_items",
"verification_status IN ('pending', 'verified', 'rejected')",
)
op.execute("""INSERT INTO audit_events (entity_type, entity_id, action, notes, snapshot)
SELECT 'knowledge_items', id, 'import', '保留基础版本数据及原状态',
json_build_object('item', row_to_json(k)) FROM knowledge_items k""")
op.execute("""UPDATE knowledge_items SET verification_status = 'pending', version = version + 1
WHERE verification_status = 'verified'""")
op.execute("""INSERT INTO audit_events (entity_type, entity_id, action, notes, snapshot)
SELECT 'knowledge_items', id, 'invalidate', '旧版本没有完整审核记录,需要重新核验',
json_build_object('item', row_to_json(k)) FROM knowledge_items k WHERE version = 2""")
def downgrade():
op.drop_constraint("ck_knowledge_verification_status", "knowledge_items", type_="check")
for name in ["source_id", "document_id"]:
op.drop_index(f"ix_knowledge_items_{name}", table_name="knowledge_items")
op.drop_constraint(f"fk_knowledge_{name}", "knowledge_items", type_="foreignkey")
for name in [
"source_id",
"document_id",
"collected_at",
"reviewer",
"reviewed_at",
"verification_notes",
"version",
"updated_at",
"is_deleted",
]:
op.drop_column("knowledge_items", name)
op.drop_table("audit_events")
op.drop_table("documents")
op.drop_table("sources")