"""Qualify pgcrypto digest in the contact sync trigger. Revision ID: 0002_pgcrypto_digest Revises: 0001_initial Create Date: 2026-07-16 """ from collections.abc import Sequence from alembic import op revision: str = "0002_pgcrypto_digest" down_revision: str | None = "0001_initial" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: op.execute( """ CREATE OR REPLACE FUNCTION han_app.enqueue_contact_sync() RETURNS trigger LANGUAGE plpgsql SECURITY INVOKER SET search_path = han_app, pg_temp AS $$ DECLARE v_entity_id uuid; v_task_type text; v_dedup text; BEGIN IF current_setting('han.sync_suppress', true) = 'true' THEN RETURN NEW; END IF; IF TG_TABLE_NAME = 'user_identities' THEN v_entity_id := NEW.id; v_task_type := CASE WHEN TG_OP = 'INSERT' THEN 'contact.map_or_create' ELSE 'contact.update' END; ELSE v_entity_id := NEW.user_id; v_task_type := CASE WHEN TG_OP = 'INSERT' THEN 'contact.map_or_create' ELSE 'contact.update' END; END IF; v_dedup := v_task_type || ':' || v_entity_id::text || ':' || encode(public.digest(row_to_json(NEW)::text, 'sha256'), 'hex'); INSERT INTO han_app.sync_queue (id, task_type, entity_type, entity_id, dedup_key, payload_json, status, attempt_count, next_attempt_at, created_at, updated_at) VALUES (gen_random_uuid(), v_task_type, 'contact', v_entity_id, v_dedup, jsonb_build_object('entity_id', v_entity_id), 'pending', 0, now(), now(), now()) ON CONFLICT (dedup_key) DO NOTHING; RETURN NEW; END; $$ """ ) def downgrade() -> None: raise RuntimeError("Contact sync trigger migration is forward-only")