-- SPDX-FileCopyrightText: 2024 Simon Bruder -- -- SPDX-License-Identifier: AGPL-3.0-or-later ALTER TABLE items ADD parent UUID REFERENCES items(id); CREATE RECURSIVE VIEW item_tree (id, parents) AS ( SELECT id, ARRAY[]::UUID[] AS parents FROM items WHERE parent IS NULL UNION SELECT items.id, item_tree.parents || items.parent FROM items, item_tree WHERE items.parent = item_tree.id ); CREATE FUNCTION check_item_cycle() RETURNS TRIGGER AS $$ BEGIN IF NEW.parent IS NULL THEN RETURN NEW; END IF; IF NEW.id = NEW.parent THEN RAISE EXCEPTION 'Cycle detected'; END IF; IF (WITH RECURSIVE cte AS ( SELECT id, parent FROM items WHERE id = NEW.parent UNION SELECT items.id, items.parent FROM items, cte WHERE items.id = cte.parent ) SELECT 1 FROM cte WHERE parent = NEW.id LIMIT 1) THEN RAISE EXCEPTION 'Cycle detected'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER prevent_item_cycle BEFORE INSERT OR UPDATE ON items FOR EACH ROW EXECUTE FUNCTION check_item_cycle();