1use futures::Stream;
2use utoipa::ToSchema;
3
4use crate::prelude::*;
5
6#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
7
8pub struct ResearchForm {
9 pub id: Uuid,
10 pub course_id: Uuid,
11 pub content: serde_json::Value,
12 pub created_at: DateTime<Utc>,
13 pub updated_at: DateTime<Utc>,
14 pub deleted_at: Option<DateTime<Utc>>,
15}
16
17#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
18
19pub struct NewResearchForm {
20 pub course_id: Uuid,
21 pub content: serde_json::Value,
22}
23
24#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
25
26pub struct ResearchFormQuestion {
27 pub id: Uuid,
28 pub course_id: Uuid,
29 pub research_consent_form_id: Uuid,
30 pub question: String,
31 pub created_at: DateTime<Utc>,
32 pub updated_at: DateTime<Utc>,
33 pub deleted_at: Option<DateTime<Utc>>,
34}
35
36#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
37
38pub struct NewResearchFormQuestion {
39 pub question_id: Uuid,
40 pub course_id: Uuid,
41 pub research_consent_form_id: Uuid,
42 pub question: String,
43}
44
45#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
46
47pub struct NewResearchFormQuestionAnswer {
48 pub user_id: Uuid,
49 pub research_form_question_id: Uuid,
50 pub research_consent: bool,
51}
52
53#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
54
55pub struct ResearchFormQuestionAnswer {
56 pub id: Uuid,
57 pub user_id: Uuid,
58 pub course_id: Uuid,
59 pub research_form_question_id: Uuid,
60 pub research_consent: bool,
61 pub created_at: DateTime<Utc>,
62 pub updated_at: DateTime<Utc>,
63 pub deleted_at: Option<DateTime<Utc>>,
64}
65
66impl NewResearchForm {
67 pub fn new(course_id: Uuid) -> Self {
69 Self {
70 course_id,
71 content: Default::default(),
72 }
73 }
74
75 pub fn set_content(mut self, content: serde_json::Value) -> Self {
77 self.content = content;
78 self
79 }
80}
81
82pub async fn upsert_research_form(
83 conn: &mut PgConnection,
84 pkey_policy: PKeyPolicy<Uuid>,
85 new_research_form: &NewResearchForm,
86) -> ModelResult<ResearchForm> {
87 let form_res = sqlx::query_as!(
88 ResearchForm,
89 "
90INSERT INTO course_specific_research_consent_forms (
91 id,
92 course_id,
93 content
94 )
95VALUES ($1, $2, $3) ON CONFLICT (course_id, deleted_at)
96DO UPDATE SET content = $3
97RETURNING *
98",
99 pkey_policy.into_uuid(),
100 new_research_form.course_id,
101 serde_json::to_value(new_research_form.content.clone())?,
102 )
103 .fetch_one(conn)
104 .await?;
105 Ok(form_res)
106}
107
108pub async fn get_research_form_with_course_id(
109 conn: &mut PgConnection,
110 course_id: Uuid,
111) -> ModelResult<ResearchForm> {
112 let form_res = sqlx::query_as!(
113 ResearchForm,
114 "
115SELECT * FROM course_specific_research_consent_forms
116WHERE course_id = $1
117AND deleted_at IS NULL
118",
119 course_id,
120 )
121 .fetch_one(conn)
122 .await?;
123 Ok(form_res)
124}
125
126pub async fn upsert_research_form_questions(
127 conn: &mut PgConnection,
128 questions: &[NewResearchFormQuestion],
129) -> ModelResult<Vec<ResearchFormQuestion>> {
130 let mut tx = conn.begin().await?;
131
132 let mut inserted_questions = Vec::new();
133
134 for question in questions {
135 let form_res = sqlx::query_as!(
136 ResearchFormQuestion,
137 "
138INSERT INTO course_specific_consent_form_questions (
139 id,
140 course_id,
141 research_consent_form_id,
142 question
143 )
144VALUES ($1, $2, $3, $4) ON CONFLICT (id)
145DO UPDATE SET question = $4,
146deleted_at = NULL
147RETURNING *
148",
149 question.question_id,
150 question.course_id,
151 question.research_consent_form_id,
152 question.question
153 )
154 .fetch_one(&mut *tx)
155 .await?;
156
157 inserted_questions.push(form_res);
158 }
159
160 tx.commit().await?;
161
162 Ok(inserted_questions)
163}
164
165pub async fn get_research_form_questions_with_course_id(
166 conn: &mut PgConnection,
167 course_id: Uuid,
168) -> ModelResult<Vec<ResearchFormQuestion>> {
169 let form_res = sqlx::query_as!(
170 ResearchFormQuestion,
171 "
172SELECT * FROM course_specific_consent_form_questions
173WHERE course_id = $1
174AND deleted_at IS NULL
175",
176 course_id,
177 )
178 .fetch_all(conn)
179 .await?;
180 Ok(form_res)
181}
182
183pub async fn get_question_by_id(
184 conn: &mut PgConnection,
185 question_id: Uuid,
186) -> ModelResult<ResearchFormQuestion> {
187 let res = sqlx::query_as!(
188 ResearchFormQuestion,
189 "
190SELECT *
191FROM course_specific_consent_form_questions
192WHERE id = $1
193 AND deleted_at IS NULL
194 ",
195 question_id
196 )
197 .fetch_one(conn)
198 .await?;
199 Ok(res)
200}
201
202pub struct ExportedCourseResearchFormQustionAnswer {
203 pub course_id: Uuid,
204 pub research_consent_form_id: Uuid,
205 pub research_form_question_id: Uuid,
206 pub question: String,
207 pub user_id: Uuid,
208 pub research_consent: bool,
209 pub created_at: DateTime<Utc>,
210 pub updated_at: DateTime<Utc>,
211}
212
213pub fn stream_course_research_form_user_answers(
214 conn: &mut PgConnection,
215 course_id: Uuid,
216) -> impl Stream<Item = sqlx::Result<ExportedCourseResearchFormQustionAnswer>> + '_ {
217 sqlx::query_as!(
218 ExportedCourseResearchFormQustionAnswer,
219 r#"
220 SELECT DISTINCT ON (a.research_form_question_id, a.user_id)
221 q.course_id,
222 q.research_consent_form_id,
223 a.research_form_question_id,
224 q.question,
225 a.user_id,
226 a.research_consent,
227 a.created_at,
228 a.updated_at
229 FROM course_specific_consent_form_answers a
230 LEFT JOIN course_specific_consent_form_questions q ON a.research_form_question_id = q.id
231 WHERE a.course_id = $1
232 AND a.deleted_at IS NULL
233 AND q.deleted_at IS NULL
234 ORDER BY a.user_id, a.research_form_question_id, a.updated_at DESC
235 "#,
236 course_id
237 )
238 .fetch(conn)
239}
240
241pub async fn upsert_research_form_anwser(
242 conn: &mut PgConnection,
243 course_id: Uuid,
244 answer: &NewResearchFormQuestionAnswer,
245) -> ModelResult<Uuid> {
246 let form_res = sqlx::query!(
247 "
248INSERT INTO course_specific_consent_form_answers (
249 user_id,
250 course_id,
251 research_form_question_id,
252 research_consent
253 )
254VALUES ($1, $2, $3, $4) ON CONFLICT (user_id, research_form_question_id)
255DO UPDATE SET research_consent = $4
256RETURNING *
257",
258 answer.user_id,
259 course_id,
260 answer.research_form_question_id,
261 answer.research_consent
262 )
263 .fetch_one(conn)
264 .await?;
265 Ok(form_res.id)
266}
267
268pub async fn upsert_answer_for_user_id_and_question_id(
269 conn: &mut PgConnection,
270 user_id: Uuid,
271 course_id: Uuid,
272 question_id: Uuid,
273 research_consent: bool,
274) -> ModelResult<Uuid> {
275 let res = sqlx::query!(
276 "
277INSERT INTO course_specific_consent_form_answers (
278 user_id,
279 course_id,
280 research_form_question_id,
281 research_consent
282)
283SELECT $1, q.course_id, q.id, $4
284FROM course_specific_consent_form_questions q
285WHERE q.id = $2
286 AND q.course_id = $3
287 AND q.deleted_at IS NULL
288ON CONFLICT (user_id, research_form_question_id)
289DO UPDATE SET
290 course_id = excluded.course_id,
291 research_consent = excluded.research_consent,
292 deleted_at = NULL
293RETURNING id
294 ",
295 user_id,
296 question_id,
297 course_id,
298 research_consent
299 )
300 .fetch_one(conn)
301 .await?;
302 Ok(res.id)
303}
304
305pub async fn get_research_form_answers_with_user_id(
306 conn: &mut PgConnection,
307 course_id: Uuid,
308 user_id: Uuid,
309) -> ModelResult<Vec<ResearchFormQuestionAnswer>> {
310 let form_res = sqlx::query_as!(
311 ResearchFormQuestionAnswer,
312 "
313SELECT * FROM course_specific_consent_form_answers
314WHERE course_id = $1 AND user_id = $2
315AND deleted_at IS NULL
316",
317 course_id,
318 user_id
319 )
320 .fetch_all(conn)
321 .await?;
322 Ok(form_res)
323}
324
325pub async fn get_all_research_form_answers_with_user_id(
326 conn: &mut PgConnection,
327 user_id: Uuid,
328) -> ModelResult<Vec<ResearchFormQuestionAnswer>> {
329 let form_res = sqlx::query_as!(
330 ResearchFormQuestionAnswer,
331 "
332SELECT * FROM course_specific_consent_form_answers
333WHERE user_id = $1
334AND deleted_at IS NULL
335",
336 user_id
337 )
338 .fetch_all(conn)
339 .await?;
340 Ok(form_res)
341}
342
343pub async fn get_all_research_form_answers_with_user_course_and_question_id(
344 conn: &mut PgConnection,
345 user_id: Uuid,
346 course_id: Uuid,
347 course_specific_consent_form_question_id: Uuid,
348) -> ModelResult<Vec<ResearchFormQuestionAnswer>> {
349 let form_res = sqlx::query_as!(
350 ResearchFormQuestionAnswer,
351 "
352SELECT * FROM course_specific_consent_form_answers
353WHERE user_id = $1
354AND course_id = $2
355AND research_form_question_id = $3
356AND deleted_at IS NULL
357",
358 user_id,
359 course_id,
360 course_specific_consent_form_question_id
361 )
362 .fetch_all(conn)
363 .await?;
364 Ok(form_res)
365}