Files
wursor/supabase/migrations/002_artboard_ancestry.sql
T
2026-05-04 12:30:56 +01:00

60 lines
2.7 KiB
PL/PgSQL

-- ── Migration 002: Artboard Ancestry Guard ───────────────────────────────────
-- The artboard_ancestry closure table and its maintenance trigger are already
-- created in migration 001 (initial schema). This migration is a safe, idempotent
-- guard that ensures the trigger function and trigger exist as expected.
--
-- IMPORTANT: An earlier draft of this file attempted to create a MATERIALIZED
-- VIEW named artboard_ancestry, which would conflict with the table created in
-- 001. That approach has been superseded: the trigger-based closure table from
-- 001 is maintained incrementally (O(depth) per INSERT) which is far cheaper
-- than a full REFRESH MATERIALIZED VIEW CONCURRENTLY on every artboard insert.
-- Do NOT re-introduce the materialized view approach.
-- ── Ensure the ancestry maintenance trigger function exists ───────────────────
-- Uses CREATE OR REPLACE so the migration is idempotent; safe to re-run.
CREATE OR REPLACE FUNCTION maintain_artboard_ancestry()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
-- Self-row: every artboard is its own ancestor at depth 0.
INSERT INTO artboard_ancestry (artboard_id, ancestor_id, depth)
VALUES (NEW.id, NEW.id, 0)
ON CONFLICT DO NOTHING;
-- Inherit all ancestors of the parent at depth + 1.
IF NEW.parent_artboard_id IS NOT NULL THEN
INSERT INTO artboard_ancestry (artboard_id, ancestor_id, depth)
SELECT NEW.id, ancestor_id, depth + 1
FROM artboard_ancestry
WHERE artboard_id = NEW.parent_artboard_id
ON CONFLICT DO NOTHING;
END IF;
RETURN NEW;
END;
$$;
-- ── Ensure the trigger is attached ───────────────────────────────────────────
-- DROP + recreate is the idempotent way to ensure the trigger is attached
-- exactly once; IF NOT EXISTS for triggers requires PG 17+ so use this pattern.
DROP TRIGGER IF EXISTS artboards_ancestry_insert ON artboards;
CREATE TRIGGER artboards_ancestry_insert
AFTER INSERT ON artboards
FOR EACH ROW EXECUTE FUNCTION maintain_artboard_ancestry();
-- ── RPC helper: get all descendants of an artboard ───────────────────────────
-- Complements getArtboardAncestors() in origin-graph/queries.ts.
-- Returns direct + transitive descendants, ordered nearest-first.
CREATE OR REPLACE FUNCTION get_artboard_descendants(p_artboard_id UUID)
RETURNS TABLE (artboard_id UUID, depth INTEGER)
LANGUAGE SQL STABLE AS $$
SELECT artboard_id, depth
FROM artboard_ancestry
WHERE ancestor_id = p_artboard_id
AND artboard_id <> p_artboard_id -- exclude self
ORDER BY depth, artboard_id;
$$;