139 lines
6.2 KiB
Python
139 lines
6.2 KiB
Python
"""add semantic facts
|
|
|
|
Revision ID: 20260415_add_semantic_facts
|
|
Revises: 20260415_add_query_route_memories
|
|
Create Date: 2026-04-15
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
revision = "20260415_add_semantic_facts"
|
|
down_revision = "20260415_add_query_route_memories"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def _table_exists(bind, table_name: str) -> bool:
|
|
return sa.inspect(bind).has_table(table_name)
|
|
|
|
|
|
def upgrade() -> None:
|
|
bind = op.get_bind()
|
|
if not _table_exists(bind, "semantic_facts"):
|
|
op.create_table(
|
|
"semantic_facts",
|
|
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
sa.Column("tenant_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("created_at", sa.TIMESTAMP(), server_default=sa.func.now(), nullable=False),
|
|
sa.Column("updated_at", sa.TIMESTAMP(), server_default=sa.func.now(), nullable=False),
|
|
sa.Column("entity_type", sa.String(length=32), nullable=False),
|
|
sa.Column("entity_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("fact_namespace", sa.String(length=64), nullable=False),
|
|
sa.Column("fact_key", sa.String(length=64), nullable=False),
|
|
sa.Column("fact_value_text", sa.Text(), nullable=False),
|
|
sa.Column("fact_value_norm", sa.String(length=255), nullable=False),
|
|
sa.Column("value_type", sa.String(length=32), nullable=False),
|
|
sa.Column("confidence", sa.Float(), nullable=False, server_default="0"),
|
|
sa.Column("evidence_source_type", sa.String(length=32), nullable=True),
|
|
sa.Column("evidence_source_id", sa.BigInteger(), nullable=True),
|
|
sa.Column("evidence_excerpt", sa.Text(), nullable=True),
|
|
sa.Column("extract_version", sa.String(length=64), nullable=True),
|
|
sa.Column("freshness_at", sa.String(length=64), nullable=True),
|
|
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
|
|
sa.UniqueConstraint(
|
|
"tenant_id",
|
|
"entity_type",
|
|
"entity_id",
|
|
"fact_key",
|
|
"fact_value_norm",
|
|
name="uq_semantic_facts_tenant_entity_key_norm",
|
|
),
|
|
)
|
|
op.create_index("ix_semantic_facts_tenant_id", "semantic_facts", ["tenant_id"], unique=False)
|
|
op.create_index("ix_semantic_facts_entity_type", "semantic_facts", ["entity_type"], unique=False)
|
|
op.create_index("ix_semantic_facts_entity_id", "semantic_facts", ["entity_id"], unique=False)
|
|
op.create_index("ix_semantic_facts_fact_namespace", "semantic_facts", ["fact_namespace"], unique=False)
|
|
op.create_index("ix_semantic_facts_fact_key", "semantic_facts", ["fact_key"], unique=False)
|
|
op.create_index("ix_semantic_facts_fact_value_norm", "semantic_facts", ["fact_value_norm"], unique=False)
|
|
op.create_index("ix_semantic_facts_is_active", "semantic_facts", ["is_active"], unique=False)
|
|
|
|
if not _table_exists(bind, "semantic_fact_extraction_runs"):
|
|
op.create_table(
|
|
"semantic_fact_extraction_runs",
|
|
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
sa.Column("tenant_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("created_at", sa.TIMESTAMP(), server_default=sa.func.now(), nullable=False),
|
|
sa.Column("updated_at", sa.TIMESTAMP(), server_default=sa.func.now(), nullable=False),
|
|
sa.Column("entity_type", sa.String(length=32), nullable=False),
|
|
sa.Column("entity_id", sa.BigInteger(), nullable=False),
|
|
sa.Column("trigger_type", sa.String(length=32), nullable=False),
|
|
sa.Column("status", sa.String(length=32), nullable=False),
|
|
sa.Column("input_fingerprint", sa.String(length=64), nullable=True),
|
|
sa.Column("facts_written", sa.Integer(), nullable=False, server_default="0"),
|
|
sa.Column("failure_reason", sa.Text(), nullable=True),
|
|
sa.Column("extract_version", sa.String(length=64), nullable=True),
|
|
sa.Column("started_at", sa.String(length=64), nullable=True),
|
|
sa.Column("finished_at", sa.String(length=64), nullable=True),
|
|
)
|
|
op.create_index(
|
|
"ix_semantic_fact_extraction_runs_tenant_id",
|
|
"semantic_fact_extraction_runs",
|
|
["tenant_id"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_semantic_fact_extraction_runs_entity_type",
|
|
"semantic_fact_extraction_runs",
|
|
["entity_type"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_semantic_fact_extraction_runs_entity_id",
|
|
"semantic_fact_extraction_runs",
|
|
["entity_id"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_semantic_fact_extraction_runs_status",
|
|
"semantic_fact_extraction_runs",
|
|
["status"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_semantic_fact_extraction_runs_input_fingerprint",
|
|
"semantic_fact_extraction_runs",
|
|
["input_fingerprint"],
|
|
unique=False,
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
bind = op.get_bind()
|
|
if _table_exists(bind, "semantic_fact_extraction_runs"):
|
|
for index_name in (
|
|
"ix_semantic_fact_extraction_runs_input_fingerprint",
|
|
"ix_semantic_fact_extraction_runs_status",
|
|
"ix_semantic_fact_extraction_runs_entity_id",
|
|
"ix_semantic_fact_extraction_runs_entity_type",
|
|
"ix_semantic_fact_extraction_runs_tenant_id",
|
|
):
|
|
op.drop_index(index_name, table_name="semantic_fact_extraction_runs")
|
|
op.drop_table("semantic_fact_extraction_runs")
|
|
|
|
if _table_exists(bind, "semantic_facts"):
|
|
for index_name in (
|
|
"ix_semantic_facts_is_active",
|
|
"ix_semantic_facts_fact_value_norm",
|
|
"ix_semantic_facts_fact_key",
|
|
"ix_semantic_facts_fact_namespace",
|
|
"ix_semantic_facts_entity_id",
|
|
"ix_semantic_facts_entity_type",
|
|
"ix_semantic_facts_tenant_id",
|
|
):
|
|
op.drop_index(index_name, table_name="semantic_facts")
|
|
op.drop_table("semantic_facts")
|