48 lines
2.8 KiB
PL/PgSQL
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();
|