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