diff --git a/backend/migrations/versions/e8b3f1a6c2d4_profile_history_reads.py b/backend/migrations/versions/e8b3f1a6c2d4_profile_history_reads.py new file mode 100644 index 0000000..691aad1 --- /dev/null +++ b/backend/migrations/versions/e8b3f1a6c2d4_profile_history_reads.py @@ -0,0 +1,52 @@ +"""profile history reads + +Revision ID: e8b3f1a6c2d4 +Revises: d8e3b5a1c7f4 +Create Date: 2026-10-19 03:00:00.000000 + +""" + +from collections.abc import Sequence + +from alembic import op + +revision: str = "e8b3f1a6c2d4" +down_revision: str | None = "d8e3b5a1c7f4" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + +_PEER_STATE = ( + "first_name, last_name, username, phone, photo_unique_id, is_deleted_account" +) + + +def upgrade() -> None: + op.execute( + "ALTER TABLE peer_history DROP CONSTRAINT peer_history_pkey, " + "ADD CONSTRAINT peer_history_pkey " + f"PRIMARY KEY (account_id, peer_id, observed_at) INCLUDE ({_PEER_STATE})" + ) + op.execute( + "ALTER TABLE chat_history DROP CONSTRAINT chat_history_pkey, " + "ADD CONSTRAINT chat_history_pkey " + "PRIMARY KEY (account_id, chat_id, message_id, ts)" + ) + op.execute( + "CREATE INDEX ix_memberships_user ON memberships (account_id, user_id, ts DESC)" + ) + op.execute( + "CREATE INDEX ix_jobs_kind_created ON jobs (account_id, kind, created_at DESC)" + ) + + +def downgrade() -> None: + op.execute("DROP INDEX IF EXISTS ix_jobs_kind_created") + op.execute("DROP INDEX IF EXISTS ix_memberships_user") + op.execute( + "ALTER TABLE chat_history DROP CONSTRAINT chat_history_pkey, " + "ADD CONSTRAINT chat_history_pkey PRIMARY KEY (account_id, chat_id, message_id)" + ) + op.execute( + "ALTER TABLE peer_history DROP CONSTRAINT peer_history_pkey, " + "ADD CONSTRAINT peer_history_pkey PRIMARY KEY (account_id, peer_id, observed_at)" + ) diff --git a/backend/src/utils/db/models.py b/backend/src/utils/db/models.py index 55cca3a..30fc3b9 100644 --- a/backend/src/utils/db/models.py +++ b/backend/src/utils/db/models.py @@ -356,7 +356,7 @@ class ChatHistory(SQLModel, table=True): title: str | None = None photo_unique_id: str | None = None actor_id: int | None = Field(default=None, sa_column=Column(BigInteger)) - ts: datetime = Field(sa_column=Column(DateTime(timezone=True), nullable=False)) + ts: datetime = Field(sa_column=Column(DateTime(timezone=True), primary_key=True)) raw: dict[str, Any] = Field( default_factory=dict, sa_column=Column(JSONB, nullable=False) )