141 lines
5.5 KiB
Python
141 lines
5.5 KiB
Python
|
|
"""Chapter evidence snapshots + normalized links (Phase C)
|
||
|
|
|
||
|
|
Revision ID: 0010_ce_snapshots (short id: alembic_version.version_num is VARCHAR(32))
|
||
|
|
Revises: 0009_ce_bundle_mem_trace
|
||
|
|
"""
|
||
|
|
|
||
|
|
from typing import Sequence, Union
|
||
|
|
|
||
|
|
import sqlalchemy as sa
|
||
|
|
from sqlalchemy.dialects import postgresql
|
||
|
|
|
||
|
|
from alembic import op
|
||
|
|
|
||
|
|
revision: str = "0010_ce_snapshots"
|
||
|
|
down_revision: Union[str, None] = "0009_ce_bundle_mem_trace"
|
||
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
||
|
|
depends_on: Union[str, Sequence[str], None] = None
|
||
|
|
|
||
|
|
|
||
|
|
def _has_table(name: str) -> bool:
|
||
|
|
bind = op.get_bind()
|
||
|
|
return sa.inspect(bind).has_table(name)
|
||
|
|
|
||
|
|
|
||
|
|
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 upgrade() -> None:
|
||
|
|
if not _has_table("chapter_evidence_snapshots"):
|
||
|
|
op.create_table(
|
||
|
|
"chapter_evidence_snapshots",
|
||
|
|
sa.Column("id", sa.String(), nullable=False),
|
||
|
|
sa.Column("chapter_id", sa.String(), nullable=False),
|
||
|
|
sa.Column("user_id", sa.String(), nullable=False),
|
||
|
|
sa.Column("version_no", sa.Integer(), nullable=False),
|
||
|
|
sa.Column("schema_version", sa.Integer(), nullable=False, server_default="1"),
|
||
|
|
sa.Column("segment_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("conversation_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("story_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("memory_chunk_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("memory_fact_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("timeline_event_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("summary_ids", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column("notes", postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||
|
|
sa.Column(
|
||
|
|
"captured_at",
|
||
|
|
sa.DateTime(timezone=True),
|
||
|
|
nullable=False,
|
||
|
|
server_default=sa.text("now()"),
|
||
|
|
),
|
||
|
|
sa.ForeignKeyConstraint(
|
||
|
|
["chapter_id"],
|
||
|
|
["chapters.id"],
|
||
|
|
name="chapter_evidence_snapshots_chapter_id_fkey",
|
||
|
|
ondelete="CASCADE",
|
||
|
|
),
|
||
|
|
sa.ForeignKeyConstraint(
|
||
|
|
["user_id"],
|
||
|
|
["users.id"],
|
||
|
|
name="chapter_evidence_snapshots_user_id_fkey",
|
||
|
|
),
|
||
|
|
sa.PrimaryKeyConstraint("id", name="chapter_evidence_snapshots_pkey"),
|
||
|
|
sa.UniqueConstraint(
|
||
|
|
"chapter_id",
|
||
|
|
"version_no",
|
||
|
|
name="uq_chapter_evidence_snapshots_chapter_version",
|
||
|
|
),
|
||
|
|
)
|
||
|
|
op.create_index(
|
||
|
|
"ix_chapter_evidence_snapshots_chapter_id",
|
||
|
|
"chapter_evidence_snapshots",
|
||
|
|
["chapter_id"],
|
||
|
|
)
|
||
|
|
op.create_index(
|
||
|
|
"ix_chapter_evidence_snapshots_user_id",
|
||
|
|
"chapter_evidence_snapshots",
|
||
|
|
["user_id"],
|
||
|
|
)
|
||
|
|
|
||
|
|
if not _has_table("chapter_evidence_links"):
|
||
|
|
op.create_table(
|
||
|
|
"chapter_evidence_links",
|
||
|
|
sa.Column("id", sa.String(), nullable=False),
|
||
|
|
sa.Column("chapter_id", sa.String(), nullable=False),
|
||
|
|
sa.Column("evidence_type", sa.String(), nullable=False),
|
||
|
|
sa.Column("evidence_id", sa.String(), nullable=False),
|
||
|
|
sa.Column("role", sa.String(), nullable=True),
|
||
|
|
sa.Column("weight", sa.Float(), nullable=True),
|
||
|
|
sa.Column(
|
||
|
|
"created_at",
|
||
|
|
sa.DateTime(timezone=True),
|
||
|
|
server_default=sa.text("now()"),
|
||
|
|
nullable=False,
|
||
|
|
),
|
||
|
|
sa.ForeignKeyConstraint(
|
||
|
|
["chapter_id"],
|
||
|
|
["chapters.id"],
|
||
|
|
name="chapter_evidence_links_chapter_id_fkey",
|
||
|
|
ondelete="CASCADE",
|
||
|
|
),
|
||
|
|
sa.PrimaryKeyConstraint("id", name="chapter_evidence_links_pkey"),
|
||
|
|
)
|
||
|
|
op.create_index(
|
||
|
|
"ix_chapter_evidence_links_chapter_id",
|
||
|
|
"chapter_evidence_links",
|
||
|
|
["chapter_id"],
|
||
|
|
)
|
||
|
|
|
||
|
|
if not _has_column("chapters", "current_evidence_snapshot_id"):
|
||
|
|
op.add_column(
|
||
|
|
"chapters",
|
||
|
|
sa.Column("current_evidence_snapshot_id", sa.String(), nullable=True),
|
||
|
|
)
|
||
|
|
op.create_foreign_key(
|
||
|
|
"fk_chapters_current_evidence_snapshot_id",
|
||
|
|
"chapters",
|
||
|
|
"chapter_evidence_snapshots",
|
||
|
|
["current_evidence_snapshot_id"],
|
||
|
|
["id"],
|
||
|
|
ondelete="SET NULL",
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def downgrade() -> None:
|
||
|
|
if _has_column("chapters", "current_evidence_snapshot_id"):
|
||
|
|
op.drop_constraint(
|
||
|
|
"fk_chapters_current_evidence_snapshot_id",
|
||
|
|
"chapters",
|
||
|
|
type_="foreignkey",
|
||
|
|
)
|
||
|
|
op.drop_column("chapters", "current_evidence_snapshot_id")
|
||
|
|
if _has_table("chapter_evidence_links"):
|
||
|
|
op.drop_index("ix_chapter_evidence_links_chapter_id", table_name="chapter_evidence_links")
|
||
|
|
op.drop_table("chapter_evidence_links")
|
||
|
|
if _has_table("chapter_evidence_snapshots"):
|
||
|
|
op.drop_index("ix_chapter_evidence_snapshots_user_id", table_name="chapter_evidence_snapshots")
|
||
|
|
op.drop_index("ix_chapter_evidence_snapshots_chapter_id", table_name="chapter_evidence_snapshots")
|
||
|
|
op.drop_table("chapter_evidence_snapshots")
|