feat(db): add migration 0104 issue polymorphic project
zhenyi committed
Added lib/db/migrations/sql/0104_issue_polymorphic_project.sql lib/db/migrations/sql/0104_issue_polymorphic_project.sql +66 −0 View lib/db/migrations/sql/0104_issue_polymorphic_project.sql
@@ -0,0 +1,66 @@
1-- 0104_issue_polymorphic_project.sql
2-- Make issue collaboration dimensions (comment / reaction / watch / event_line
3-- / pin) polymorphic between issue and project. Each row must reference
4-- exactly one of (issue_id, comment_id for reactions, project_id).
5--
6-- Documentation only; not run by the migration runner per project policy.
7
8-- ---------------------------------------------------------------------------
9-- comment : (issue_id XOR project_id)
10-- ---------------------------------------------------------------------------
11ALTER TABLE comment
12 ALTER COLUMN issue_id DROP NOT NULL,
13 ADD COLUMN IF NOT EXISTS project_id uuid REFERENCES project(id) ON DELETE CASCADE,
14 ADD CONSTRAINT comment_target_xor
15 CHECK ((issue_id IS NOT NULL) <> (project_id IS NOT NULL));
16CREATE INDEX IF NOT EXISTS idx_comment_project ON comment (project_id);
17
18-- ---------------------------------------------------------------------------
19-- issue_reaction : exactly one of (issue_id, comment_id, project_id)
20-- ---------------------------------------------------------------------------
21ALTER TABLE issue_reaction
22 ADD COLUMN IF NOT EXISTS project_id uuid REFERENCES project(id) ON DELETE CASCADE,
23 ADD CONSTRAINT issue_reaction_target_exactly_one
24 CHECK (
25 ((issue_id IS NOT NULL)::int +
26 (comment_id IS NOT NULL)::int +
27 (project_id IS NOT NULL)::int) = 1
28 );
29CREATE INDEX IF NOT EXISTS idx_issue_reaction_project ON issue_reaction (project_id);
30
31-- ---------------------------------------------------------------------------
32-- issue_watch : (issue_id XOR project_id)
33-- ---------------------------------------------------------------------------
34ALTER TABLE issue_watch
35 ALTER COLUMN issue_id DROP NOT NULL,
36 ADD COLUMN IF NOT EXISTS project_id uuid REFERENCES project(id) ON DELETE CASCADE,
37 ADD CONSTRAINT issue_watch_target_xor
38 CHECK ((issue_id IS NOT NULL) <> (project_id IS NOT NULL));
39CREATE INDEX IF NOT EXISTS idx_issue_watch_project ON issue_watch (project_id);
40
41-- Rebuild unique indexes with partial filter so nullable columns are handled:
42DROP INDEX IF EXISTS idx_issue_watch_issue_user;
43CREATE UNIQUE INDEX IF NOT EXISTS idx_issue_watch_issue_user
44 ON issue_watch (issue_id, user_id) WHERE issue_id IS NOT NULL;
45CREATE UNIQUE INDEX IF NOT EXISTS idx_issue_watch_project_user
46 ON issue_watch (project_id, user_id) WHERE project_id IS NOT NULL;
47
48-- ---------------------------------------------------------------------------
49-- issue_event_line : (issue_id XOR project_id)
50-- ---------------------------------------------------------------------------
51ALTER TABLE issue_event_line
52 ALTER COLUMN issue_id DROP NOT NULL,
53 ADD COLUMN IF NOT EXISTS project_id uuid REFERENCES project(id) ON DELETE CASCADE,
54 ADD CONSTRAINT issue_event_target_xor
55 CHECK ((issue_id IS NOT NULL) <> (project_id IS NOT NULL));
56CREATE INDEX IF NOT EXISTS idx_issue_event_project ON issue_event_line (project_id);
57
58-- ---------------------------------------------------------------------------
59-- issue_pin : (issue_id XOR project_id)
60-- ---------------------------------------------------------------------------
61ALTER TABLE issue_pin
62 ALTER COLUMN issue_id DROP NOT NULL,
63 ADD COLUMN IF NOT EXISTS project_id uuid REFERENCES project(id) ON DELETE CASCADE,
64 ADD CONSTRAINT issue_pin_target_xor
65 CHECK ((issue_id IS NOT NULL) <> (project_id IS NOT NULL));
66CREATE INDEX IF NOT EXISTS idx_issue_pin_project ON issue_pin (project_id);