Skip to main content

headless_lms_models/library/credit_registration/
submission_context.rs

1//! Everything a submission needs that does not live on the ledger row yet. One query rather than a
2//! lookup per row: the phases work in batches of up to a thousand.
3
4use std::collections::HashMap;
5
6use crate::prelude::*;
7
8use super::payload::CompletionFacts;
9
10/// The module's fields, the linked student number and the completion, for one ledger row.
11#[derive(Debug, Clone)]
12pub struct SubmissionContext {
13    pub registration_id: Uuid,
14    /// `None` once the account's number has been unlinked.
15    pub student_number: Option<DbSecret>,
16    pub sisu_person_id: Option<DbSecret>,
17    pub uh_course_code: Option<String>,
18    pub ects_credits: Option<f32>,
19    pub completion: CompletionFacts,
20}
21
22/// The per-row facts each phase needs to act on a batch of ledger rows without a lookup per row.
23pub async fn get_submission_contexts(
24    conn: &mut PgConnection,
25    registration_ids: &[Uuid],
26) -> ModelResult<HashMap<Uuid, SubmissionContext>> {
27    let rows = sqlx::query!(
28        r#"
29-- Nullability is stated for the outer-joined columns rather than inferred: sqlx-cli 0.9.0 derives
30-- them the wrong way round, and an offline build of this query then fails to compile.
31SELECT cr.id,
32  vsn.student_number AS "student_number?",
33  vsn.sisu_person_id AS "sisu_person_id?",
34  cm.uh_course_code,
35  cm.ects_credits,
36  cmc.passed,
37  cmc.grade,
38  cmc.completion_date,
39  cmc.completion_language
40FROM credit_registrations cr
41  JOIN course_module_completions cmc ON cmc.id = cr.course_module_completion_id
42  AND cmc.deleted_at IS NULL
43  JOIN course_modules cm ON cm.id = cr.course_module_id
44  AND cm.deleted_at IS NULL
45  LEFT JOIN verified_student_numbers vsn ON vsn.user_id = cr.user_id
46  AND vsn.deleted_at IS NULL
47WHERE cr.id = ANY($1::uuid [])
48  AND cr.deleted_at IS NULL
49        "#,
50        registration_ids,
51    )
52    .fetch_all(conn)
53    .await?;
54    Ok(rows
55        .into_iter()
56        .map(|row| {
57            (
58                row.id,
59                SubmissionContext {
60                    registration_id: row.id,
61                    student_number: row.student_number,
62                    sisu_person_id: row.sisu_person_id,
63                    uh_course_code: row.uh_course_code,
64                    ects_credits: row.ects_credits,
65                    completion: CompletionFacts {
66                        passed: row.passed,
67                        grade: row.grade,
68                        completion_date: row.completion_date,
69                        completion_language: row.completion_language,
70                    },
71                },
72            )
73        })
74        .collect())
75}