98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""chat stats last deleted
|
|
|
|
Revision ID: f1c4a8e2d6b3
|
|
Revises: e8b3f1a6c2d4
|
|
Create Date: 2026-10-19 04:00:00.000000
|
|
|
|
"""
|
|
|
|
from collections.abc import Sequence
|
|
|
|
from alembic import op
|
|
|
|
revision: str = "f1c4a8e2d6b3"
|
|
down_revision: str | None = "e8b3f1a6c2d4"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
_APPLY = """
|
|
CREATE OR REPLACE FUNCTION chat_stats_apply() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF TG_OP = 'INSERT' THEN
|
|
INSERT INTO chat_stats AS cs (account_id, chat_id, message_count,
|
|
last_date, last_message_id,
|
|
last_text, last_sender_id{column})
|
|
VALUES (NEW.account_id, NEW.chat_id, 1,
|
|
CASE WHEN NEW.date <= now() + interval '1 day'
|
|
THEN NEW.date END,
|
|
CASE WHEN NEW.date <= now() + interval '1 day'
|
|
THEN NEW.message_id END,
|
|
NEW.text, NEW.sender_id{value})
|
|
ON CONFLICT (account_id, chat_id) DO UPDATE SET
|
|
message_count = cs.message_count + 1,
|
|
last_date = CASE WHEN chat_stats_newer(cs, EXCLUDED)
|
|
THEN EXCLUDED.last_date ELSE cs.last_date END,
|
|
last_message_id = CASE WHEN chat_stats_newer(cs, EXCLUDED)
|
|
THEN EXCLUDED.last_message_id
|
|
ELSE cs.last_message_id END,
|
|
last_text = CASE WHEN chat_stats_newer(cs, EXCLUDED)
|
|
THEN EXCLUDED.last_text ELSE cs.last_text END,
|
|
last_sender_id = CASE WHEN chat_stats_newer(cs, EXCLUDED)
|
|
THEN EXCLUDED.last_sender_id
|
|
ELSE cs.last_sender_id END{merge};
|
|
ELSE
|
|
UPDATE chat_stats
|
|
SET last_text = NEW.text, last_sender_id = NEW.sender_id{update}
|
|
WHERE account_id = NEW.account_id
|
|
AND chat_id = NEW.chat_id
|
|
AND last_message_id = NEW.message_id;
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$
|
|
"""
|
|
|
|
_DELETED_PARTS = {
|
|
"column": ", last_deleted",
|
|
"value": ", NEW.deleted_at IS NOT NULL",
|
|
"merge": (
|
|
",\n last_deleted = CASE WHEN chat_stats_newer(cs, EXCLUDED)"
|
|
" THEN EXCLUDED.last_deleted ELSE cs.last_deleted END"
|
|
),
|
|
"update": ", last_deleted = NEW.deleted_at IS NOT NULL",
|
|
"deleted": " OR OLD.deleted_at IS DISTINCT FROM NEW.deleted_at",
|
|
}
|
|
_PLAIN_PARTS = dict.fromkeys(_DELETED_PARTS, "")
|
|
|
|
_UPDATE_TRIGGER = (
|
|
"CREATE TRIGGER messages_chat_stats_update AFTER UPDATE ON messages "
|
|
"FOR EACH ROW WHEN (OLD.text IS DISTINCT FROM NEW.text "
|
|
"OR OLD.sender_id IS DISTINCT FROM NEW.sender_id{deleted}) "
|
|
"EXECUTE FUNCTION chat_stats_apply()"
|
|
)
|
|
|
|
_BACKFILL = """
|
|
UPDATE chat_stats cs SET last_deleted = true
|
|
FROM messages m
|
|
WHERE m.account_id = cs.account_id AND m.chat_id = cs.chat_id
|
|
AND m.message_id = cs.last_message_id AND m.date = cs.last_date
|
|
AND m.deleted_at IS NOT NULL
|
|
"""
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.execute(
|
|
"ALTER TABLE chat_stats ADD COLUMN last_deleted boolean NOT NULL DEFAULT false"
|
|
)
|
|
op.execute(_BACKFILL)
|
|
op.execute(_APPLY.format(**_DELETED_PARTS))
|
|
op.execute("DROP TRIGGER IF EXISTS messages_chat_stats_update ON messages")
|
|
op.execute(_UPDATE_TRIGGER.format(**_DELETED_PARTS))
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.execute("DROP TRIGGER IF EXISTS messages_chat_stats_update ON messages")
|
|
op.execute(_UPDATE_TRIGGER.format(**_PLAIN_PARTS))
|
|
op.execute(_APPLY.format(**_PLAIN_PARTS))
|
|
op.execute("ALTER TABLE chat_stats DROP COLUMN last_deleted")
|