headless_lms_models/
user_course_exercise_service_variables.rs

1use std::collections::HashMap;
2
3use crate::{exercise_tasks::ExerciseTask, prelude::*, user_exercise_states::UserExerciseState};
4
5#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
6#[cfg_attr(feature = "ts_rs", derive(TS))]
7pub struct UserCourseExerciseServiceVariable {
8    pub id: Uuid,
9    pub created_at: DateTime<Utc>,
10    pub updated_at: DateTime<Utc>,
11    pub deleted_at: Option<DateTime<Utc>>,
12    pub exercise_service_slug: String,
13    pub user_id: Uuid,
14    pub course_id: Option<Uuid>,
15    pub exam_id: Option<Uuid>,
16    pub variable_key: String,
17    pub variable_value: serde_json::Value,
18}
19
20pub(crate) async fn get_all_variables_for_user_and_course_or_exam(
21    conn: &mut PgConnection,
22    user_id: Uuid,
23    instance_or_exam_id: CourseOrExamId,
24) -> ModelResult<Vec<UserCourseExerciseServiceVariable>> {
25    let (course_id, exam_id) = instance_or_exam_id.to_course_and_exam_ids();
26    let res = sqlx::query_as!(
27        UserCourseExerciseServiceVariable,
28        r#"
29SELECT *
30FROM user_course_exercise_service_variables
31WHERE deleted_at IS NULL
32  AND user_id = $1
33  AND (course_id = $2 OR course_id IS NULL)
34  AND (exam_id = $3 OR exam_id IS NULL);
35    "#,
36        user_id,
37        course_id,
38        exam_id
39    )
40    .fetch_all(conn)
41    .await?;
42    Ok(res)
43}
44
45pub async fn get_all_user_variables_for_user_and_course_and_exercise_type(
46    conn: &mut PgConnection,
47    user_id: Uuid,
48    course_id: Uuid,
49    exercise_type: &str,
50) -> ModelResult<Vec<UserCourseExerciseServiceVariable>> {
51    let res = sqlx::query_as!(
52        UserCourseExerciseServiceVariable,
53        r#"
54SELECT *
55FROM user_course_exercise_service_variables
56WHERE deleted_at IS NULL
57  AND user_id = $1
58  AND course_id = $2
59  AND exercise_service_slug = $3;
60    "#,
61        user_id,
62        course_id,
63        exercise_type
64    )
65    .fetch_all(conn)
66    .await?;
67    Ok(res)
68}
69
70pub(crate) async fn insert_after_exercise_task_graded(
71    conn: &mut PgConnection,
72    set_user_variables: &Option<HashMap<String, serde_json::Value>>,
73    exercise_task: &ExerciseTask,
74    user_exercise_state: &UserExerciseState,
75) -> ModelResult<()> {
76    if let Some(set_user_variables) = set_user_variables {
77        for (k, v) in set_user_variables {
78            sqlx::query!(
79                r#"
80INSERT INTO user_course_exercise_service_variables (
81    exercise_service_slug,
82    user_id,
83    course_id,
84    exam_id,
85    variable_key,
86    variable_value
87  )
88VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (
89    variable_key,
90    user_id,
91    course_id,
92    exercise_service_slug,
93    exam_id,
94    deleted_at
95  ) DO
96UPDATE
97SET variable_value = $6;
98    "#,
99                exercise_task.exercise_type,
100                user_exercise_state.user_id,
101                user_exercise_state.course_id,
102                user_exercise_state.exam_id,
103                k,
104                v
105            )
106            .execute(&mut *conn)
107            .await?;
108        }
109        Ok(())
110    } else {
111        Ok(())
112    }
113}