headless_lms_models/
course_background_question_answers.rs1use crate::{course_background_questions::CourseBackgroundQuestion, prelude::*};
2use utoipa::ToSchema;
3
4#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
5
6pub struct CourseBackgroundQuestionAnswer {
7 pub id: Uuid,
8 pub created_at: DateTime<Utc>,
9 pub updated_at: DateTime<Utc>,
10 pub deleted_at: Option<DateTime<Utc>>,
11 pub course_background_question_id: Uuid,
12 pub answer_value: Option<String>,
13 pub user_id: Uuid,
14}
15
16#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
17
18pub struct NewCourseBackgroundQuestionAnswer {
19 pub answer_value: Option<String>,
20 pub course_background_question_id: Uuid,
21}
22
23pub async fn get_background_question_answers_for_background_questions(
24 conn: &mut PgConnection,
25 user_id: Uuid,
26 background_questions: &[CourseBackgroundQuestion],
27) -> ModelResult<Vec<CourseBackgroundQuestionAnswer>> {
28 let ids = background_questions
29 .iter()
30 .map(|o| o.id)
31 .collect::<Vec<_>>();
32 let res: Vec<CourseBackgroundQuestionAnswer> = sqlx::query_as!(
33 CourseBackgroundQuestionAnswer,
34 r#"
35SELECT *
36FROM course_background_question_answers
37WHERE deleted_at IS NULL
38AND user_id = $1
39AND course_background_question_id IN (
40 SELECT UNNEST($2::uuid [])
41 )
42 "#,
43 user_id,
44 &ids,
45 )
46 .fetch_all(conn)
47 .await?;
48 Ok(res)
49}
50
51pub async fn upsert_backround_question_answers(
52 conn: &mut PgConnection,
53 user_id: Uuid,
54 background_question_answers: &[NewCourseBackgroundQuestionAnswer],
55) -> ModelResult<()> {
56 let mut tx = conn.begin().await?;
57 for answer in background_question_answers {
58 sqlx::query!(
59 r#"
60INSERT INTO course_background_question_answers (
61 course_background_question_id,
62 user_id,
63 answer_value
64 )
65VALUES ($1, $2, $3) ON CONFLICT (
66 course_background_question_id,
67 user_id,
68 deleted_at
69 ) DO
70UPDATE
71SET answer_value = $3
72 "#,
73 answer.course_background_question_id,
74 user_id,
75 answer.answer_value
76 )
77 .execute(&mut *tx)
78 .await?;
79 }
80
81 tx.commit().await?;
82
83 Ok(())
84}
85
86pub async fn upsert_by_user_id_and_question_ids(
91 conn: &mut PgConnection,
92 user_id: Uuid,
93 background_question_answers: &[NewCourseBackgroundQuestionAnswer],
94 allowed_question_ids: &[Uuid],
95) -> ModelResult<()> {
96 let mut tx = conn.begin().await?;
97 for answer in background_question_answers {
98 let result = sqlx::query!(
99 r#"
100INSERT INTO course_background_question_answers (
101 course_background_question_id,
102 user_id,
103 answer_value
104)
105SELECT q.id, $2, $3
106FROM course_background_questions q
107WHERE q.id = $1
108 AND q.id = ANY($4)
109 AND q.deleted_at IS NULL
110ON CONFLICT (
111 course_background_question_id,
112 user_id,
113 deleted_at
114) DO UPDATE SET answer_value = EXCLUDED.answer_value
115 "#,
116 answer.course_background_question_id,
117 user_id,
118 answer.answer_value,
119 allowed_question_ids
120 )
121 .execute(&mut *tx)
122 .await;
123
124 let result = match result {
125 Ok(result) => result,
126 Err(err) => {
127 tx.rollback().await?;
128 return Err(err.into());
129 }
130 };
131
132 if result.rows_affected() == 0 {
133 tx.rollback().await?;
134 return Err(model_err!(
135 PreconditionFailed,
136 "Background question is not in the allowed question set"
137 ));
138 }
139 }
140
141 tx.commit().await?;
142
143 Ok(())
144}