-- name: UpsertStudentAnswer :one INSERT INTO student_answers ( assignment_id, question_id, student_id, answer_text, solve_mode, working_steps, ai_feedback, teacher_feedback, status, submitted_at, reviewed_at, is_correct ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 ) ON CONFLICT (assignment_id, question_id, student_id) DO UPDATE SET answer_text = EXCLUDED.answer_text, solve_mode = EXCLUDED.solve_mode, working_steps = EXCLUDED.working_steps, ai_feedback = EXCLUDED.ai_feedback, teacher_feedback = EXCLUDED.teacher_feedback, status = EXCLUDED.status, submitted_at = EXCLUDED.submitted_at, reviewed_at = EXCLUDED.reviewed_at, is_correct = EXCLUDED.is_correct, updated_at = NOW() RETURNING *; -- name: UpdateAnswerAIReview :one UPDATE student_answers SET ai_feedback = $2, review_needs_attention = $3, review_issue_reason = $4, review_correctness_score = $5, review_understanding_score = $6, review_question_score = $7, review_confidence = $8, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: ListAnswersForAssignment :many SELECT * FROM student_answers WHERE assignment_id = $1 ORDER BY created_at ASC; -- name: ListAnswersForStudent :many SELECT * FROM student_answers WHERE student_id = $1 ORDER BY created_at DESC; -- name: ListQuestionDetailsForAssignmentStudent :many WITH student_question_set AS ( SELECT asq.assignment_id, asq.question_id, asq.position FROM assignment_student_questions asq WHERE asq.assignment_id = $1 AND asq.student_id = $2 ), selected_questions AS ( SELECT sq.assignment_id, sq.question_id, sq.position FROM student_question_set sq UNION ALL SELECT aq.assignment_id, aq.question_id, aq.position FROM assignment_questions aq WHERE aq.assignment_id = $1 AND NOT EXISTS (SELECT 1 FROM student_question_set) ) SELECT aq.assignment_id, aq.question_id, aq.position, q.title, q.prompt, q.subject, q.source, COALESCE( ARRAY( SELECT t.name FROM question_tags qt JOIN tags t ON t.id = qt.tag_id WHERE qt.question_id = aq.question_id ORDER BY t.name ASC ), ARRAY[]::TEXT[] )::TEXT[] AS question_tags, q.status AS question_status, q.correct_answer, aa.ai_feedback AS assignment_ai_feedback, aa.teacher_feedback AS assignment_teacher_feedback, review_summary.overall_score, a.pass_threshold, aa.next_step_outcome, aa.pass_status_override, COALESCE( aa.pass_status_override, CASE WHEN review_summary.overall_score IS NULL THEN 'pending'::assignment_pass_status WHEN review_summary.overall_score >= a.pass_threshold THEN 'pass'::assignment_pass_status ELSE 'no_pass'::assignment_pass_status END ) AS pass_status, sa.id AS answer_id, sa.student_id, sa.answer_text, sa.solve_mode, sa.working_steps, sa.is_correct, sa.ai_feedback, sa.teacher_feedback, sa.status AS answer_status, sa.review_needs_attention, sa.review_issue_reason, sa.review_correctness_score, sa.review_understanding_score, sa.review_question_score, sa.review_confidence, sa.review_tags, sa.submitted_at, sa.reviewed_at, sa.created_at AS answer_created_at, sa.updated_at AS answer_updated_at FROM selected_questions aq JOIN assignments a ON a.id = aq.assignment_id JOIN questions q ON q.id = aq.question_id LEFT JOIN assignment_assignees aa ON aa.assignment_id = aq.assignment_id AND aa.student_id = $2 LEFT JOIN LATERAL ( SELECT CASE WHEN COUNT(sa2.id) = 0 THEN NULL::NUMERIC(5,2) ELSE ROUND((AVG( CASE WHEN sa2.is_correct IS NULL THEN COALESCE(sa2.review_understanding_score, 0)::NUMERIC ELSE ( ((CASE WHEN sa2.is_correct THEN 1 ELSE 0 END)::NUMERIC) + COALESCE(sa2.review_understanding_score, 0)::NUMERIC ) / 2 END ) * 10)::NUMERIC, 2)::NUMERIC(5,2) END AS overall_score FROM selected_questions aq2 LEFT JOIN student_answers sa2 ON sa2.assignment_id = aq2.assignment_id AND sa2.question_id = aq2.question_id AND sa2.student_id = $2 WHERE aq2.assignment_id = aq.assignment_id ) review_summary ON TRUE LEFT JOIN student_answers sa ON sa.assignment_id = aq.assignment_id AND sa.question_id = aq.question_id AND sa.student_id = $2 WHERE aq.assignment_id = $1 ORDER BY aq.position ASC, aq.question_id ASC; -- name: UpdateAnswerReview :one UPDATE student_answers SET status = $2, review_needs_attention = $3, review_issue_reason = $4, review_correctness_score = $5, review_understanding_score = $6, review_question_score = $7, review_confidence = $8, review_tags = $9, reviewed_at = CASE WHEN $2::answer_status = 'reviewed' THEN NOW() ELSE NULL END, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: ListStudentPlanningPerformance :many SELECT sa.assignment_id, sa.question_id, q.topic, q.subject, q.difficulty, COALESCE( ARRAY( SELECT t.name FROM question_tags qt JOIN tags t ON t.id = qt.tag_id WHERE qt.question_id = sa.question_id ORDER BY t.name ASC ), ARRAY[]::TEXT[] )::TEXT[] AS question_tags, sa.is_correct, sa.review_understanding_score, sa.review_needs_attention, sa.review_issue_reason, sa.status, sa.submitted_at, sa.reviewed_at, sa.updated_at FROM student_answers sa JOIN questions q ON q.id = sa.question_id WHERE sa.student_id = $1 AND sa.status IN ('submitted'::answer_status, 'reviewed'::answer_status) ORDER BY COALESCE(sa.reviewed_at, sa.submitted_at, sa.updated_at) DESC, sa.id DESC;