1use crate::prelude::*;
2use chrono::{DateTime, Utc};
3use sqlx::PgConnection;
4use utoipa::ToSchema;
5use uuid::Uuid;
6
7#[derive(Debug, Serialize, Deserialize, FromRow, PartialEq, Clone, ToSchema)]
8
9pub struct MaterialReference {
10 pub id: Uuid,
11 pub course_id: Uuid,
12 pub citation_key: String,
13 pub reference: String,
14 pub created_at: DateTime<Utc>,
15 pub updated_at: DateTime<Utc>,
16 pub deleted_at: Option<DateTime<Utc>>,
17}
18
19#[derive(Debug, Serialize, Deserialize, FromRow, PartialEq, Clone, ToSchema)]
20
21pub struct NewMaterialReference {
22 pub citation_key: String,
23 pub reference: String,
24}
25
26pub async fn insert_reference(
27 conn: &mut PgConnection,
28 course_id: Uuid,
29 new_ref: Vec<NewMaterialReference>,
30) -> ModelResult<()> {
31 let mut tx = conn.begin().await?;
32 let new_ref_iter = new_ref.iter();
33
34 for new_ref in new_ref_iter {
35 sqlx::query!(
36 "
37 INSERT INTO material_references(course_id, citation_key, reference)
38 VALUES ($1, $2, $3)
39 ",
40 course_id,
41 new_ref.citation_key,
42 new_ref.reference
43 )
44 .execute(&mut *tx)
45 .await?;
46 }
47 tx.commit().await?;
48
49 Ok(())
50}
51
52pub async fn get_reference_by_id(
53 conn: &mut PgConnection,
54 reference_id: Uuid,
55) -> ModelResult<MaterialReference> {
56 let res = sqlx::query_as!(
57 MaterialReference,
58 "
59SELECT *
60FROM material_references
61WHERE id = $1;
62 ",
63 reference_id
64 )
65 .fetch_one(conn)
66 .await?;
67 Ok(res)
68}
69
70pub async fn get_non_deleted_by_id(
71 conn: &mut PgConnection,
72 reference_id: Uuid,
73) -> ModelResult<MaterialReference> {
74 let res = sqlx::query_as!(
75 MaterialReference,
76 "
77SELECT *
78FROM material_references
79WHERE id = $1
80 AND deleted_at IS NULL;
81 ",
82 reference_id
83 )
84 .fetch_one(conn)
85 .await?;
86 Ok(res)
87}
88
89pub async fn get_references_by_course_id(
90 conn: &mut PgConnection,
91 course_id: Uuid,
92) -> ModelResult<Vec<MaterialReference>> {
93 let res = sqlx::query_as!(
94 MaterialReference,
95 "
96SELECT *
97FROM material_references
98WHERE course_id = $1
99 AND deleted_at IS NULL;
100 ",
101 course_id
102 )
103 .fetch_all(conn)
104 .await?;
105 Ok(res)
106}
107
108pub async fn get_by_ids(
110 conn: &mut PgConnection,
111 ids: &[Uuid],
112) -> ModelResult<Vec<MaterialReference>> {
113 let res = sqlx::query_as!(
114 MaterialReference,
115 "
116SELECT *
117FROM material_references
118WHERE id = ANY($1)
119 AND deleted_at IS NULL
120 ",
121 ids
122 )
123 .fetch_all(conn)
124 .await?;
125 Ok(res)
126}
127
128pub async fn update_material_reference_by_id(
129 conn: &mut PgConnection,
130 material_reference_id: Uuid,
131 material_reference: NewMaterialReference,
132) -> ModelResult<()> {
133 sqlx::query!(
134 "
135UPDATE material_references
136SET reference = $1, citation_key = $2
137WHERE id = $3;
138",
139 material_reference.reference,
140 material_reference.citation_key,
141 material_reference_id
142 )
143 .execute(conn)
144 .await?;
145 Ok(())
146}
147
148pub async fn update_by_id_and_course_id(
149 conn: &mut PgConnection,
150 material_reference_id: Uuid,
151 course_id: Uuid,
152 material_reference: NewMaterialReference,
153) -> ModelResult<MaterialReference> {
154 let res = sqlx::query_as!(
155 MaterialReference,
156 "
157UPDATE material_references
158SET reference = $1,
159 citation_key = $2
160WHERE id = $3
161 AND course_id = $4
162 AND deleted_at IS NULL
163RETURNING *
164 ",
165 material_reference.reference,
166 material_reference.citation_key,
167 material_reference_id,
168 course_id
169 )
170 .fetch_one(conn)
171 .await?;
172 Ok(res)
173}
174
175pub async fn delete_reference(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
176 sqlx::query!(
177 "
178UPDATE material_references
179SET deleted_at = now()
180WHERE material_references.id = $1
181AND deleted_at IS NULL;
182 ",
183 id
184 )
185 .execute(conn)
186 .await?;
187 Ok(())
188}
189
190pub async fn delete_by_id_and_course_id(
191 conn: &mut PgConnection,
192 id: Uuid,
193 course_id: Uuid,
194) -> ModelResult<MaterialReference> {
195 let res = sqlx::query_as!(
196 MaterialReference,
197 "
198UPDATE material_references
199SET deleted_at = now()
200WHERE id = $1
201 AND course_id = $2
202 AND deleted_at IS NULL
203RETURNING *
204 ",
205 id,
206 course_id
207 )
208 .fetch_one(conn)
209 .await?;
210 Ok(res)
211}
212
213pub async fn upsert_from_snapshot(
216 conn: &mut PgConnection,
217 snapshot: &crate::library::entity_snapshots::ReferenceSnapshot,
218) -> ModelResult<()> {
219 sqlx::query!(
220 "
221INSERT INTO material_references (id, course_id, citation_key, reference)
222VALUES ($1, $2, $3, $4) ON CONFLICT (id) DO
223UPDATE
224SET citation_key = EXCLUDED.citation_key,
225 reference = EXCLUDED.reference,
226 deleted_at = NULL
227WHERE material_references.course_id = EXCLUDED.course_id
228",
229 snapshot.id,
230 snapshot.course_id,
231 snapshot.citation_key,
232 snapshot.reference,
233 )
234 .execute(conn)
235 .await?;
236 Ok(())
237}