Yimaru-BackEnd/db/migrations/000024_subcourse_entry_assessment_and_sub_levels.up.sql

149 lines
3.8 KiB
PL/PgSQL

-- Add sub-level support to sub_courses and enforce valid level/sub-level combinations.
ALTER TABLE sub_courses
ADD COLUMN sub_level VARCHAR(2);
UPDATE sub_courses
SET sub_level = CASE level
WHEN 'BEGINNER' THEN 'A1'
WHEN 'INTERMEDIATE' THEN 'B1'
WHEN 'ADVANCED' THEN 'C1'
ELSE 'A1'
END
WHERE sub_level IS NULL;
ALTER TABLE sub_courses
ALTER COLUMN sub_level SET NOT NULL;
ALTER TABLE sub_courses
ADD CONSTRAINT sub_courses_level_sub_level_check CHECK (
(level = 'BEGINNER' AND sub_level IN ('A1', 'A2', 'A3')) OR
(level = 'INTERMEDIATE' AND sub_level IN ('B1', 'B2', 'B3')) OR
(level = 'ADVANCED' AND sub_level IN ('C1', 'C2', 'C3'))
);
CREATE INDEX idx_sub_courses_level_sub_level ON sub_courses(level, sub_level);
-- Ensure each sub-course has an entry-assessment question set.
CREATE UNIQUE INDEX idx_question_sets_unique_subcourse_initial_assessment
ON question_sets(owner_type, owner_id, set_type)
WHERE owner_type = 'SUB_COURSE' AND set_type = 'INITIAL_ASSESSMENT' AND status != 'ARCHIVED';
CREATE OR REPLACE FUNCTION clone_default_initial_assessment_items(target_set_id BIGINT)
RETURNS VOID AS $$
DECLARE
template_set_id BIGINT;
BEGIN
SELECT id
INTO template_set_id
FROM question_sets
WHERE set_type = 'INITIAL_ASSESSMENT'
AND owner_type = 'STANDALONE'
AND status = 'PUBLISHED'
ORDER BY created_at DESC
LIMIT 1;
IF template_set_id IS NULL THEN
RETURN;
END IF;
INSERT INTO question_set_items (set_id, question_id, display_order)
SELECT target_set_id, qsi.question_id, qsi.display_order
FROM question_set_items qsi
WHERE qsi.set_id = template_set_id
AND NOT EXISTS (
SELECT 1
FROM question_set_items existing
WHERE existing.set_id = target_set_id
AND existing.question_id = qsi.question_id
);
END;
$$ LANGUAGE plpgsql;
INSERT INTO question_sets (
title,
description,
set_type,
owner_type,
owner_id,
shuffle_questions,
status
)
SELECT
sc.title || ' Entry Assessment',
'Entry assessment used to evaluate learners before joining this sub-course.',
'INITIAL_ASSESSMENT',
'SUB_COURSE',
sc.id,
false,
'DRAFT'
FROM sub_courses sc
WHERE NOT EXISTS (
SELECT 1
FROM question_sets qs
WHERE qs.owner_type = 'SUB_COURSE'
AND qs.owner_id = sc.id
AND qs.set_type = 'INITIAL_ASSESSMENT'
AND qs.status != 'ARCHIVED'
);
DO $$
DECLARE
r RECORD;
BEGIN
FOR r IN
SELECT id
FROM question_sets
WHERE owner_type = 'SUB_COURSE'
AND set_type = 'INITIAL_ASSESSMENT'
AND status != 'ARCHIVED'
LOOP
IF NOT EXISTS (SELECT 1 FROM question_set_items WHERE set_id = r.id) THEN
PERFORM clone_default_initial_assessment_items(r.id);
END IF;
END LOOP;
END;
$$;
CREATE OR REPLACE FUNCTION create_sub_course_entry_assessment()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO question_sets (
title,
description,
set_type,
owner_type,
owner_id,
shuffle_questions,
status
)
VALUES (
NEW.title || ' Entry Assessment',
'Entry assessment used to evaluate learners before joining this sub-course.',
'INITIAL_ASSESSMENT',
'SUB_COURSE',
NEW.id,
false,
'DRAFT'
)
ON CONFLICT DO NOTHING;
PERFORM clone_default_initial_assessment_items((
SELECT id
FROM question_sets
WHERE owner_type = 'SUB_COURSE'
AND owner_id = NEW.id
AND set_type = 'INITIAL_ASSESSMENT'
AND status != 'ARCHIVED'
ORDER BY created_at DESC
LIMIT 1
));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_sub_courses_create_entry_assessment
AFTER INSERT ON sub_courses
FOR EACH ROW
EXECUTE FUNCTION create_sub_course_entry_assessment();