234 lines
7.3 KiB
PL/PgSQL
234 lines
7.3 KiB
PL/PgSQL
-- Migration: CMS CRUD Functions
|
|
-- Encapsulate all data mutations in stored functions
|
|
|
|
-- 1. Course Management
|
|
CREATE OR REPLACE FUNCTION fn_create_course(
|
|
p_organization_id UUID,
|
|
p_instructor_id UUID,
|
|
p_title VARCHAR(255),
|
|
p_pacing_mode VARCHAR(50) DEFAULT 'self_paced'
|
|
) RETURNS SETOF courses AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
INSERT INTO courses (organization_id, instructor_id, title, pacing_mode)
|
|
VALUES (p_organization_id, p_instructor_id, p_title, p_pacing_mode)
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION fn_update_course(
|
|
p_id UUID,
|
|
p_organization_id UUID,
|
|
p_title VARCHAR(255),
|
|
p_description TEXT,
|
|
p_passing_percentage INTEGER,
|
|
p_pacing_mode VARCHAR(50),
|
|
p_start_date TIMESTAMPTZ,
|
|
p_end_date TIMESTAMPTZ,
|
|
p_certificate_template VARCHAR(255) DEFAULT NULL
|
|
) RETURNS SETOF courses AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
UPDATE courses
|
|
SET title = p_title,
|
|
description = p_description,
|
|
passing_percentage = p_passing_percentage,
|
|
pacing_mode = p_pacing_mode,
|
|
start_date = p_start_date,
|
|
end_date = p_end_date,
|
|
certificate_template = p_certificate_template,
|
|
updated_at = NOW()
|
|
WHERE id = p_id AND organization_id = p_organization_id
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION fn_delete_course(
|
|
p_id UUID,
|
|
p_organization_id UUID
|
|
) RETURNS BOOLEAN AS $$
|
|
DECLARE
|
|
v_deleted_count INTEGER;
|
|
BEGIN
|
|
DELETE FROM courses
|
|
WHERE id = p_id AND organization_id = p_organization_id;
|
|
|
|
GET DIAGNOSTICS v_deleted_count = ROW_COUNT;
|
|
RETURN v_deleted_count > 0;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 2. Module Management
|
|
CREATE OR REPLACE FUNCTION fn_create_module(
|
|
p_organization_id UUID,
|
|
p_course_id UUID,
|
|
p_title VARCHAR(255),
|
|
p_position INTEGER
|
|
) RETURNS SETOF modules AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
INSERT INTO modules (organization_id, course_id, title, position)
|
|
VALUES (p_organization_id, p_course_id, p_title, p_position)
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION fn_update_module(
|
|
p_id UUID,
|
|
p_organization_id UUID,
|
|
p_title VARCHAR(255) DEFAULT NULL,
|
|
p_position INTEGER DEFAULT NULL
|
|
) RETURNS SETOF modules AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
UPDATE modules
|
|
SET title = COALESCE(p_title, title),
|
|
position = COALESCE(p_position, position),
|
|
updated_at = NOW()
|
|
WHERE id = p_id AND organization_id = p_organization_id
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 3. Lesson Management
|
|
CREATE OR REPLACE FUNCTION fn_create_lesson(
|
|
p_organization_id UUID,
|
|
p_module_id UUID,
|
|
p_title VARCHAR(255),
|
|
p_content_type VARCHAR(50),
|
|
p_content_url VARCHAR(500) DEFAULT NULL,
|
|
p_position INTEGER DEFAULT 0,
|
|
p_transcription JSONB DEFAULT NULL,
|
|
p_metadata JSONB DEFAULT NULL,
|
|
p_is_graded BOOLEAN DEFAULT FALSE,
|
|
p_grading_category_id UUID DEFAULT NULL,
|
|
p_max_attempts INTEGER DEFAULT NULL,
|
|
p_allow_retry BOOLEAN DEFAULT TRUE,
|
|
p_due_date TIMESTAMPTZ DEFAULT NULL,
|
|
p_important_date_type VARCHAR(50) DEFAULT NULL
|
|
) RETURNS SETOF lessons AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
INSERT INTO lessons (
|
|
organization_id, module_id, title, content_type, content_url,
|
|
position, transcription, metadata, is_graded, grading_category_id,
|
|
max_attempts, allow_retry, due_date, important_date_type
|
|
)
|
|
VALUES (
|
|
p_organization_id, p_module_id, p_title, p_content_type, p_content_url,
|
|
p_position, p_transcription, p_metadata, p_is_graded, p_grading_category_id,
|
|
p_max_attempts, p_allow_retry, p_due_date, p_important_date_type
|
|
)
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION fn_update_lesson(
|
|
p_id UUID,
|
|
p_organization_id UUID,
|
|
p_title VARCHAR(255) DEFAULT NULL,
|
|
p_content_type VARCHAR(50) DEFAULT NULL,
|
|
p_content_url VARCHAR(500) DEFAULT NULL,
|
|
p_content_blocks JSONB DEFAULT NULL,
|
|
p_transcription JSONB DEFAULT NULL,
|
|
p_metadata JSONB DEFAULT NULL,
|
|
p_is_graded BOOLEAN DEFAULT NULL,
|
|
p_grading_category_id UUID DEFAULT NULL,
|
|
p_max_attempts INTEGER DEFAULT NULL,
|
|
p_allow_retry BOOLEAN DEFAULT NULL,
|
|
p_position INTEGER DEFAULT NULL,
|
|
p_due_date TIMESTAMPTZ DEFAULT NULL,
|
|
p_important_date_type VARCHAR(50) DEFAULT NULL,
|
|
p_summary TEXT DEFAULT NULL,
|
|
p_clear_due_date BOOLEAN DEFAULT FALSE,
|
|
p_clear_grading_category BOOLEAN DEFAULT FALSE
|
|
) RETURNS SETOF lessons AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
UPDATE lessons
|
|
SET title = COALESCE(p_title, title),
|
|
content_type = COALESCE(p_content_type, content_type),
|
|
content_url = COALESCE(p_content_url, content_url),
|
|
content_blocks = COALESCE(p_content_blocks, content_blocks),
|
|
transcription = COALESCE(p_transcription, transcription),
|
|
metadata = COALESCE(p_metadata, metadata),
|
|
is_graded = COALESCE(p_is_graded, is_graded),
|
|
grading_category_id = CASE
|
|
WHEN p_clear_grading_category THEN NULL
|
|
ELSE COALESCE(p_grading_category_id, grading_category_id)
|
|
END,
|
|
max_attempts = COALESCE(p_max_attempts, max_attempts),
|
|
allow_retry = COALESCE(p_allow_retry, allow_retry),
|
|
position = COALESCE(p_position, position),
|
|
due_date = CASE
|
|
WHEN p_clear_due_date THEN NULL
|
|
ELSE COALESCE(p_due_date, due_date)
|
|
END,
|
|
important_date_type = COALESCE(p_important_date_type, important_date_type),
|
|
summary = COALESCE(p_summary, summary),
|
|
updated_at = NOW()
|
|
WHERE id = p_id AND organization_id = p_organization_id
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 4. Content Reordering
|
|
CREATE OR REPLACE PROCEDURE pr_reorder_modules(
|
|
p_organization_id UUID,
|
|
p_updates JSONB -- Array of {id, position}
|
|
) AS $$
|
|
DECLARE
|
|
v_update JSONB;
|
|
BEGIN
|
|
FOR v_update IN SELECT * FROM jsonb_array_elements(p_updates)
|
|
LOOP
|
|
UPDATE modules
|
|
SET position = (v_update->>'position')::INTEGER
|
|
WHERE id = (v_update->>'id')::UUID AND organization_id = p_organization_id;
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE PROCEDURE pr_reorder_lessons(
|
|
p_organization_id UUID,
|
|
p_updates JSONB -- Array of {id, position}
|
|
) AS $$
|
|
DECLARE
|
|
v_update JSONB;
|
|
BEGIN
|
|
FOR v_update IN SELECT * FROM jsonb_array_elements(p_updates)
|
|
LOOP
|
|
UPDATE lessons
|
|
SET position = (v_update->>'position')::INTEGER
|
|
WHERE id = (v_update->>'id')::UUID AND organization_id = p_organization_id;
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 5. User & Auth Management
|
|
CREATE OR REPLACE FUNCTION fn_register_user(
|
|
p_email VARCHAR(255),
|
|
p_password_hash VARCHAR(255),
|
|
p_full_name VARCHAR(255),
|
|
p_role VARCHAR(50),
|
|
p_org_name VARCHAR(255) -- Preserved for signature compatibility but ignored
|
|
) RETURNS SETOF users AS $$
|
|
DECLARE
|
|
v_org_id UUID := '00000000-0000-0000-0000-000000000001';
|
|
BEGIN
|
|
-- Create user in default organization
|
|
RETURN QUERY
|
|
INSERT INTO users (email, password_hash, full_name, role, organization_id)
|
|
VALUES (p_email, p_password_hash, p_full_name, p_role, v_org_id)
|
|
RETURNING *;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION fn_get_user_by_email(
|
|
p_email VARCHAR(255)
|
|
) RETURNS SETOF users AS $$
|
|
BEGIN
|
|
RETURN QUERY SELECT * FROM users WHERE email = p_email;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|