Files
appks/migrate/005_issue_workspace_upgrade.sql
2026-06-07 11:30:56 +08:00

125 lines
4.6 KiB
SQL

-- 005: Issue workspace-level upgrade + slug removal
-- 1. Drop slug from workspace
-- 2. Lift issue from repo-level to workspace-level (repo_id -> workspace_id)
-- 3. Add issue_repo_relation for multi-repo association
-- 4. Add milestone_id to issue
-- 5. Add missing unique constraints
ALTER TABLE workspace DROP COLUMN IF EXISTS slug;
CREATE UNIQUE INDEX IF NOT EXISTS uq_workspace_name ON workspace (lower(name)) WHERE deleted_at IS NULL;
DROP INDEX IF EXISTS idx_issue_repo_id;
DROP INDEX IF EXISTS idx_issue_repo_created;
ALTER TABLE issue DROP CONSTRAINT IF EXISTS issue_repo_id_fkey;
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'issue'
AND column_name = 'repo_id'
)
AND NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'issue'
AND column_name = 'workspace_id'
) THEN
ALTER TABLE issue RENAME COLUMN repo_id TO workspace_id;
END IF;
END $$;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'issue_workspace_id_fkey'
AND conrelid = 'issue'::regclass
) THEN
ALTER TABLE issue
ADD CONSTRAINT issue_workspace_id_fkey
FOREIGN KEY (workspace_id) REFERENCES workspace(id) ON DELETE CASCADE;
END IF;
END $$;
CREATE INDEX IF NOT EXISTS idx_issue_workspace_id ON issue (workspace_id);
CREATE INDEX IF NOT EXISTS idx_issue_ws_created ON issue (workspace_id, created_at DESC);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'uq_issue_workspace_number'
AND conrelid = 'issue'::regclass
) THEN
ALTER TABLE issue
ADD CONSTRAINT uq_issue_workspace_number UNIQUE (workspace_id, number);
END IF;
END $$;
CREATE TABLE IF NOT EXISTS issue_repo_relation (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
issue_id UUID NOT NULL REFERENCES issue(id) ON DELETE CASCADE,
repo_id UUID NOT NULL REFERENCES repo(id) ON DELETE CASCADE,
relation_type TEXT NOT NULL,
created_by UUID NULL REFERENCES "user"(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL,
CONSTRAINT uq_issue_repo_relation UNIQUE (issue_id, repo_id)
);
CREATE INDEX IF NOT EXISTS idx_issue_repo_relation_issue_id
ON issue_repo_relation (issue_id);
CREATE INDEX IF NOT EXISTS idx_issue_repo_relation_repo_id
ON issue_repo_relation (repo_id);
ALTER TABLE issue
ADD COLUMN IF NOT EXISTS milestone_id UUID NULL REFERENCES issue_milestone(id) ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS idx_issue_milestone_id ON issue (milestone_id);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint
WHERE conname = 'uq_issue_label_relation'
AND conrelid = 'issue_label_relation'::regclass
) THEN
ALTER TABLE issue_label_relation
ADD CONSTRAINT uq_issue_label_relation UNIQUE (issue_id, label_id);
END IF;
END $$;
CREATE UNIQUE INDEX IF NOT EXISTS uq_repo_workspace_name
ON repo (workspace_id, lower(name)) WHERE deleted_at IS NULL;
-- ─── 7. pull_request: unique number per repo ───────────────────────────
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'uq_pull_request_repo_number' AND conrelid = 'pull_request'::regclass
) THEN
ALTER TABLE pull_request
ADD CONSTRAINT uq_pull_request_repo_number UNIQUE (repo_id, number);
END IF;
END $$;
-- ─── 8. pr_label_relation: unique constraint ────────────────────────────
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'uq_pr_label_relation' AND conrelid = 'pr_label_relation'::regclass
) THEN
ALTER TABLE pr_label_relation
ADD CONSTRAINT uq_pr_label_relation UNIQUE (pull_request_id, label_id);
END IF;
END $$;