Submatter/packages/database/migrations/0021_chat_direct_membership_immutability.sql

48 lines
2.8 KiB
PL/PgSQL

CREATE FUNCTION public.enforce_chat_direct_channel_invariant() RETURNS trigger
LANGUAGE plpgsql
SET search_path = pg_catalog, public
AS $$
DECLARE canonical_key text;
DECLARE member_count integer;
BEGIN
IF OLD.kind = 'direct' AND (NEW.kind IS DISTINCT FROM OLD.kind OR NEW.direct_key IS DISTINCT FROM OLD.direct_key OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id) THEN
RAISE EXCEPTION 'direct channel identity is immutable' USING ERRCODE = '23514', CONSTRAINT = 'chat_direct_channel_identity_immutable';
END IF;
IF OLD.kind <> 'direct' AND NEW.kind = 'direct' THEN
IF NEW.workspace_id IS DISTINCT FROM OLD.workspace_id OR NEW.name IS NOT NULL OR NEW.direct_key IS NULL THEN
RAISE EXCEPTION 'invalid direct channel transition' USING ERRCODE = '23514', CONSTRAINT = 'chat_direct_channel_transition_valid';
END IF;
SELECT md5(string_agg(m.user_id::text, ':' ORDER BY m.user_id::text)), count(*)
INTO canonical_key, member_count
FROM public.chat_channel_members m
WHERE m.workspace_id = NEW.workspace_id AND m.channel_id = NEW.id;
IF member_count < 2 OR canonical_key IS DISTINCT FROM NEW.direct_key OR NOT EXISTS (
SELECT 1 FROM public.chat_channel_members m WHERE m.workspace_id = NEW.workspace_id AND m.channel_id = NEW.id AND m.user_id = NEW.owner_user_id
) THEN
RAISE EXCEPTION 'direct channel participants do not match canonical key' USING ERRCODE = '23514', CONSTRAINT = 'chat_direct_channel_participants_valid';
END IF;
END IF;
RETURN NEW;
END;
$$;
--> statement-breakpoint
REVOKE ALL ON FUNCTION public.enforce_chat_direct_channel_invariant() FROM PUBLIC;
--> statement-breakpoint
CREATE TRIGGER chat_direct_channel_invariant BEFORE UPDATE ON public.chat_channels FOR EACH ROW EXECUTE FUNCTION public.enforce_chat_direct_channel_invariant();
--> statement-breakpoint
CREATE FUNCTION public.enforce_chat_direct_membership_immutability() RETURNS trigger
LANGUAGE plpgsql
SET search_path = pg_catalog, public
AS $$
BEGIN
IF EXISTS (SELECT 1 FROM public.chat_channels c WHERE c.workspace_id = COALESCE(OLD.workspace_id, NEW.workspace_id) AND c.id = COALESCE(OLD.channel_id, NEW.channel_id) AND c.kind = 'direct')
OR (TG_OP = 'UPDATE' AND EXISTS (SELECT 1 FROM public.chat_channels c WHERE c.workspace_id = NEW.workspace_id AND c.id = NEW.channel_id AND c.kind = 'direct')) THEN
RAISE EXCEPTION 'direct channel membership is immutable' USING ERRCODE = '23514', CONSTRAINT = 'chat_direct_membership_immutable';
END IF;
RETURN COALESCE(NEW, OLD);
END;
$$;
--> statement-breakpoint
REVOKE ALL ON FUNCTION public.enforce_chat_direct_membership_immutability() FROM PUBLIC;
--> statement-breakpoint
CREATE TRIGGER chat_direct_membership_immutability BEFORE INSERT OR UPDATE OR DELETE ON public.chat_channel_members FOR EACH ROW EXECUTE FUNCTION public.enforce_chat_direct_membership_immutability();