Changes between Version 3 and Version 4 of AdvancedDB


Ignore:
Timestamp:
03/28/26 13:37:07 (2 weeks ago)
Author:
221296
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedDB

    v3 v4  
    264264
    265265}}}
    266 == Data constraints requirements: Health Record integrity
     266== Data constraints requirements: Quiz attempt validity + score consistency
    267267=== Data requirements description
    268 Health records must be consistent:
    269 * A health record must be tied to an appointment that is DONE.
    270 * The animal in health_records must match the animal of the referenced appointment.
    271 * The record date must match the appointment date.
     268Quiz attempts must obey assessment consistency rules:
     269* A quiz attempt must always refer to a valid user and a valid quiz.
     270* The achieved score must be between 0 and the quiz total_points.
     271* A user should only attempt quizzes that belong to lessons from courses in which the user is enrolled.
     272* Invalid quiz attempts are blocked
    272273=== Implementation
    273274{{{Triggers}}}
    274275{{{
    275 CREATE OR REPLACE FUNCTION petify_trg_health_records_enforce()
     276CREATE OR REPLACE FUNCTION olpms_trg_quiz_attempt_enforce()
    276277RETURNS trigger
    277278LANGUAGE plpgsql
    278279AS $$
    279280DECLARE
    280   v_appt_animal bigint;
    281   v_appt_status text;
    282   v_appt_date date;
    283 BEGIN
    284   SELECT a.animal_id, a.status, a.date_time::date
    285   INTO v_appt_animal, v_appt_status, v_appt_date
    286   FROM appointments a
    287   WHERE a.appointment_id = NEW.appointment_id;
    288 
    289   IF v_appt_animal IS NULL THEN
    290     RAISE EXCEPTION 'Appointment % not found for health record', NEW.appointment_id;
    291   END IF;
    292 
    293   IF NEW.animal_id <> v_appt_animal THEN
    294     RAISE EXCEPTION 'Health record animal_id (%) must match appointment animal_id (%) for appointment %',
    295       NEW.animal_id, v_appt_animal, NEW.appointment_id;
    296   END IF;
    297 
    298   IF v_appt_status <> 'DONE' THEN
    299     RAISE EXCEPTION 'Cannot insert health record unless appointment % is DONE (current status=%)',
    300       NEW.appointment_id, v_appt_status;
    301   END IF;
    302 
    303   IF NEW.date <> v_appt_date THEN
    304     RAISE EXCEPTION 'Health record date (%) must equal appointment date (%) for appointment %',
    305       NEW.date, v_appt_date, NEW.appointment_id;
    306   END IF;
    307 
    308   RETURN NEW;
    309 END;
    310 $$;
    311 
    312 DROP TRIGGER IF EXISTS trg_health_records_enforce ON health_records;
    313 CREATE TRIGGER trg_health_records_enforce
     281    v_total_points INT;
     282BEGIN
     283    IF NEW.user_id IS NULL THEN
     284        RAISE EXCEPTION 'Quiz attempt must reference a valid user';
     285    END IF;
     286
     287    IF NEW.quiz_id IS NULL THEN
     288        RAISE EXCEPTION 'Quiz attempt must reference a valid quiz';
     289    END IF;
     290
     291    SELECT q.total_points
     292    INTO v_total_points
     293    FROM quiz q
     294    WHERE q.quiz_id = NEW.quiz_id;
     295
     296    IF v_total_points IS NULL THEN
     297        RAISE EXCEPTION 'Quiz % does not exist', NEW.quiz_id;
     298    END IF;
     299
     300    IF NEW.score IS NULL THEN
     301        RAISE EXCEPTION 'Quiz attempt score must not be NULL';
     302    END IF;
     303
     304    IF NEW.score < 0 OR NEW.score > v_total_points THEN
     305        RAISE EXCEPTION
     306            'Invalid score % for quiz %, allowed range is 0 to %',
     307            NEW.score, NEW.quiz_id, v_total_points;
     308    END IF;
     309
     310    IF NOT EXISTS (
     311        SELECT 1
     312        FROM enrollment e
     313        JOIN module m
     314            ON m.course_id = e.course_id
     315        JOIN lesson l
     316            ON l.module_id = m.module_id
     317        JOIN quiz q
     318            ON q.lesson_id = l.lesson_id
     319        WHERE e.user_id = NEW.user_id
     320          AND q.quiz_id = NEW.quiz_id
     321    ) THEN
     322        RAISE EXCEPTION
     323            'User % is not enrolled in the course associated with quiz %',
     324            NEW.user_id, NEW.quiz_id;
     325    END IF;
     326
     327    RETURN NEW;
     328END;
     329$$;
     330
     331DROP TRIGGER IF EXISTS trg_quiz_attempt_enforce ON quiz_attempt;
     332
     333CREATE TRIGGER trg_quiz_attempt_enforce
    314334BEFORE INSERT OR UPDATE
    315 ON health_records
    316 FOR EACH ROW
    317 EXECUTE FUNCTION petify_trg_health_records_enforce();
     335ON quiz_attempt
     336FOR EACH ROW
     337EXECUTE FUNCTION olpms_trg_quiz_attempt_enforce();
    318338}}}
    319339{{{Views}}}
    320340{{{
    321 CREATE OR REPLACE VIEW v_health_records_with_context AS
     341CREATE OR REPLACE VIEW v_quiz_attempts_enriched AS
    322342SELECT
    323   hr.healthrecord_id,
    324   hr.animal_id,
    325   a.name AS animal_name,
    326   hr.appointment_id,
    327   ap.clinic_id,
    328   ap.date_time,
    329   ap.status AS appointment_status,
    330   hr.type,
    331   hr.description,
    332   hr.date
    333 FROM health_records hr
    334 JOIN animals a      ON a.animal_id = hr.animal_id
    335 JOIN appointments ap ON ap.appointment_id = hr.appointment_id;
     343    qa.attempt_id,
     344    qa.attempt_date,
     345    qa.score,
     346    qa.user_id,
     347    ue.first_name,
     348    ue.last_name,
     349    ue.email,
     350    qa.quiz_id,
     351    q.total_points,
     352    q.passing_score,
     353    l.lesson_id,
     354    l.title AS lesson_title,
     355    m.module_id,
     356    m.title AS module_title,
     357    c.course_id,
     358    c.name AS course_name,
     359    CASE
     360        WHEN qa.score >= q.passing_score THEN 'PASSED'
     361        ELSE 'FAILED'
     362    END AS result_status
     363FROM quiz_attempt qa
     364JOIN users u
     365    ON u.id = qa.user_id
     366JOIN user_entity ue
     367    ON ue.id = u.id
     368JOIN quiz q
     369    ON q.quiz_id = qa.quiz_id
     370JOIN lesson l
     371    ON l.lesson_id = q.lesson_id
     372JOIN module m
     373    ON m.module_id = l.module_id
     374JOIN course c
     375    ON c.course_id = m.course_id;
    336376}}}
    337377== Data constraints requirements: Review Consistency