Add Surat Keluar
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
-- Drop the view
|
||||
DROP VIEW IF EXISTS department_hierarchy;
|
||||
|
||||
-- Drop the functions
|
||||
DROP FUNCTION IF EXISTS get_department_hierarchy_path(UUID);
|
||||
DROP FUNCTION IF EXISTS check_department_hierarchy();
|
||||
|
||||
-- Drop the trigger
|
||||
DROP TRIGGER IF EXISTS check_department_hierarchy_trigger ON departments;
|
||||
|
||||
-- Drop the index
|
||||
DROP INDEX IF EXISTS idx_departments_parent_id;
|
||||
|
||||
-- Remove the parent_department_id column
|
||||
ALTER TABLE departments DROP COLUMN IF EXISTS parent_department_id;
|
||||
@@ -0,0 +1,128 @@
|
||||
-- 1) Schema changes
|
||||
ALTER TABLE departments
|
||||
ADD COLUMN parent_department_id UUID REFERENCES departments(id) ON DELETE CASCADE;
|
||||
|
||||
CREATE INDEX idx_departments_parent_id ON departments(parent_department_id);
|
||||
|
||||
-- (Optional but recommended for ltree lookups)
|
||||
-- CREATE EXTENSION IF NOT EXISTS ltree;
|
||||
-- CREATE INDEX idx_departments_path_gist ON departments USING GIST (path);
|
||||
-- CREATE INDEX idx_departments_path_nlevel ON departments ((nlevel(path)));
|
||||
|
||||
-- 2) Migrate parent ids from existing ltree path
|
||||
-- Use ltree helpers: nlevel() and subpath()
|
||||
UPDATE departments d1
|
||||
SET parent_department_id = d2.id
|
||||
FROM departments d2
|
||||
WHERE nlevel(d1.path) > 1
|
||||
AND d2.path = subpath(d1.path, 0, nlevel(d1.path) - 1);
|
||||
|
||||
-- 3) Guard against cycles/self-parent via trigger
|
||||
CREATE OR REPLACE FUNCTION check_department_hierarchy()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
current_id UUID;
|
||||
max_depth INT := 100;
|
||||
depth INT := 0;
|
||||
BEGIN
|
||||
IF NEW.parent_department_id IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
-- self-reference
|
||||
IF NEW.parent_department_id = NEW.id THEN
|
||||
RAISE EXCEPTION 'Department cannot be its own parent';
|
||||
END IF;
|
||||
|
||||
-- walk up the tree
|
||||
current_id := NEW.parent_department_id;
|
||||
WHILE current_id IS NOT NULL AND depth < max_depth LOOP
|
||||
IF current_id = NEW.id THEN
|
||||
RAISE EXCEPTION 'Circular reference detected in department hierarchy';
|
||||
END IF;
|
||||
|
||||
SELECT parent_department_id INTO current_id
|
||||
FROM departments
|
||||
WHERE id = current_id;
|
||||
|
||||
depth := depth + 1;
|
||||
END LOOP;
|
||||
|
||||
IF depth >= max_depth THEN
|
||||
RAISE EXCEPTION 'Department hierarchy too deep (max: %)', max_depth;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS check_department_hierarchy_trigger ON departments;
|
||||
|
||||
CREATE TRIGGER check_department_hierarchy_trigger
|
||||
BEFORE INSERT OR UPDATE OF parent_department_id ON departments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_department_hierarchy();
|
||||
|
||||
-- 4) Helper to rebuild dotted text path from codes (top.down.leaf)
|
||||
CREATE OR REPLACE FUNCTION get_department_hierarchy_path(dept_id UUID)
|
||||
RETURNS TEXT AS $$
|
||||
DECLARE
|
||||
path_text TEXT := '';
|
||||
current_dept RECORD;
|
||||
current_id UUID := dept_id;
|
||||
BEGIN
|
||||
WHILE current_id IS NOT NULL LOOP
|
||||
SELECT id, name, parent_department_id, code
|
||||
INTO current_dept
|
||||
FROM departments
|
||||
WHERE id = current_id;
|
||||
|
||||
IF current_dept IS NULL THEN
|
||||
EXIT;
|
||||
END IF;
|
||||
|
||||
IF path_text = '' THEN
|
||||
path_text := current_dept.code;
|
||||
ELSE
|
||||
path_text := current_dept.code || '.' || path_text;
|
||||
END IF;
|
||||
|
||||
current_id := current_dept.parent_department_id;
|
||||
END LOOP;
|
||||
|
||||
RETURN path_text;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 5) View for easy hierarchy queries
|
||||
CREATE OR REPLACE VIEW department_hierarchy AS
|
||||
WITH RECURSIVE dept_tree AS (
|
||||
-- roots
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
code,
|
||||
parent_department_id,
|
||||
path,
|
||||
0 AS level,
|
||||
ARRAY[id] AS hierarchy_ids,
|
||||
ARRAY[name] AS hierarchy_names
|
||||
FROM departments
|
||||
WHERE parent_department_id IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- children
|
||||
SELECT
|
||||
d.id,
|
||||
d.name,
|
||||
d.code,
|
||||
d.parent_department_id,
|
||||
d.path,
|
||||
dt.level + 1,
|
||||
dt.hierarchy_ids || d.id,
|
||||
dt.hierarchy_names || d.name
|
||||
FROM departments d
|
||||
JOIN dept_tree dt ON d.parent_department_id = dt.id
|
||||
)
|
||||
SELECT * FROM dept_tree;
|
||||
Reference in New Issue
Block a user