-- 006_add_canonical_path.sql -- 정사 경로 표시를 위한 필드 추가 -- memo_nodes 테이블에 정사 경로 관련 필드 추가 ALTER TABLE memo_nodes ADD COLUMN is_canonical BOOLEAN DEFAULT FALSE, ADD COLUMN canonical_order INTEGER DEFAULT NULL, ADD COLUMN story_path TEXT DEFAULT NULL; -- 정사 경로 저장 (예: /1/3/7) -- 정사 경로 순서를 위한 인덱스 추가 CREATE INDEX idx_memo_nodes_canonical_order ON memo_nodes(tree_id, canonical_order) WHERE is_canonical = TRUE; -- 트리별 정사 경로 통계를 위한 뷰 생성 CREATE OR REPLACE VIEW memo_tree_canonical_stats AS SELECT t.id as tree_id, t.title as tree_title, COUNT(n.id) as total_nodes, COUNT(CASE WHEN n.is_canonical = TRUE THEN 1 END) as canonical_nodes, MAX(n.canonical_order) as max_canonical_order, STRING_AGG( CASE WHEN n.is_canonical = TRUE THEN n.title END, ' → ' ORDER BY n.canonical_order ) as canonical_story_path FROM memo_trees t LEFT JOIN memo_nodes n ON t.id = n.tree_id GROUP BY t.id, t.title; -- 정사 경로 순서 자동 업데이트 함수 (분기점에서 하나만 선택 가능) CREATE OR REPLACE FUNCTION update_canonical_order() RETURNS TRIGGER AS $$ BEGIN -- 정사로 설정될 때 IF NEW.is_canonical = TRUE AND (OLD.is_canonical IS NULL OR OLD.is_canonical = FALSE) THEN -- 같은 부모를 가진 다른 형제 노드들의 정사 상태 해제 (분기점에서 하나만 선택) IF NEW.parent_id IS NOT NULL THEN UPDATE memo_nodes SET is_canonical = FALSE, canonical_order = NULL, story_path = NULL WHERE tree_id = NEW.tree_id AND parent_id = NEW.parent_id AND id != NEW.id AND is_canonical = TRUE; END IF; -- 부모 노드의 순서를 기준으로 순서 계산 IF NEW.parent_id IS NULL THEN -- 루트 노드는 항상 1 NEW.canonical_order = 1; ELSE -- 부모 노드의 순서 + 1 SELECT COALESCE(parent.canonical_order, 0) + 1 INTO NEW.canonical_order FROM memo_nodes parent WHERE parent.id = NEW.parent_id AND parent.is_canonical = TRUE; -- 부모가 정사가 아니면 순서 할당 안함 IF NEW.canonical_order IS NULL THEN NEW.canonical_order = NULL; END IF; END IF; -- 정사 경로 업데이트 NEW.story_path = COALESCE(NEW.path, ''); END IF; -- 정사에서 제외될 때 순서 제거 IF NEW.is_canonical = FALSE AND OLD.is_canonical = TRUE THEN NEW.canonical_order = NULL; NEW.story_path = NULL; -- 뒤의 순서들을 앞으로 당기기 UPDATE memo_nodes SET canonical_order = canonical_order - 1 WHERE tree_id = NEW.tree_id AND is_canonical = TRUE AND canonical_order > OLD.canonical_order; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 트리거 생성 DROP TRIGGER IF EXISTS trigger_update_canonical_order ON memo_nodes; CREATE TRIGGER trigger_update_canonical_order BEFORE UPDATE ON memo_nodes FOR EACH ROW EXECUTE FUNCTION update_canonical_order(); -- 기존 루트 노드들을 정사로 설정 (기본값) UPDATE memo_nodes SET is_canonical = TRUE, canonical_order = 1 WHERE parent_id IS NULL AND is_canonical = FALSE; COMMENT ON COLUMN memo_nodes.is_canonical IS '정사 경로 여부 (소설의 메인 스토리라인)'; COMMENT ON COLUMN memo_nodes.canonical_order IS '정사 경로에서의 순서 (1부터 시작)'; COMMENT ON COLUMN memo_nodes.story_path IS '정사 경로 문자열 표현';