tdm_server_rust/repository/
questionnaire_repo.rs1use crate::entity::questionnaire::Questionnaire;
6use chrono::{DateTime, Utc};
7use sqlx::{MySql, Pool, Row};
8
9const SELECT_COLS: &str = "id, member_id, willingness, acceptable_lengths, update_frequency, \
11 preferred_genres, avoid_topics, note, remark, last_assigned_time, created_at, updated_at";
12
13pub struct QuestionnaireRepository {
15 pool: Pool<MySql>,
17}
18
19impl QuestionnaireRepository {
20 pub fn new(pool: Pool<MySql>) -> Self {
22 Self { pool }
23 }
24
25 #[tracing::instrument(skip_all, level = "debug")]
27 pub async fn get_by_member_id(&self, member_id: i32) -> crate::error::ApiResult<Option<Questionnaire>> {
28 let sql = format!("SELECT {SELECT_COLS} FROM questionnaire WHERE member_id = ?");
29 let row = sqlx::query(&sql).bind(member_id).fetch_optional(&self.pool).await?;
30 Ok(row.map(|r| row_to_questionnaire(&r)))
31 }
32
33 #[tracing::instrument(skip_all, level = "debug")]
35 pub async fn list_all(
36 &self,
37 willingness: Option<i16>,
38 length: Option<&str>,
39 frequency: Option<i16>,
40 member_id: Option<i32>,
41 ) -> crate::error::ApiResult<Vec<Questionnaire>> {
42 let mut sql = format!("SELECT {SELECT_COLS} FROM questionnaire WHERE 1=1");
43 if willingness.is_some() {
44 sql.push_str(" AND willingness = ?");
45 }
46 if length.is_some() {
47 sql.push_str(" AND acceptable_lengths = ?");
48 }
49 if frequency.is_some() {
50 sql.push_str(" AND update_frequency = ?");
51 }
52 if member_id.is_some() {
53 sql.push_str(" AND member_id = ?");
54 }
55 let mut q = sqlx::query(&sql);
56 if let Some(v) = willingness {
57 q = q.bind(v);
58 }
59 if let Some(v) = length {
60 q = q.bind(v);
61 }
62 if let Some(v) = frequency {
63 q = q.bind(v);
64 }
65 if let Some(v) = member_id {
66 q = q.bind(v);
67 }
68 let rows = q.fetch_all(&self.pool).await?;
69 Ok(rows.into_iter().map(|r| row_to_questionnaire(&r)).collect())
70 }
71
72 #[tracing::instrument(skip_all, level = "debug")]
74 pub async fn list_by_post(
75 &self,
76 post_id: i32,
77 willingness: Option<i16>,
78 length: Option<&str>,
79 frequency: Option<i16>,
80 member_id: Option<i32>,
81 ) -> crate::error::ApiResult<Vec<Questionnaire>> {
82 let mut sql = format!(
83 "SELECT q.id, q.member_id, q.willingness, q.acceptable_lengths, q.update_frequency, \
84 q.preferred_genres, q.avoid_topics, q.note, q.remark, q.last_assigned_time, \
85 q.created_at, q.updated_at \
86 FROM questionnaire q \
87 INNER JOIN memberpost mp ON q.member_id = mp.memberId \
88 WHERE mp.postId = ?"
89 );
90 if willingness.is_some() {
91 sql.push_str(" AND q.willingness = ?");
92 }
93 if length.is_some() {
94 sql.push_str(" AND q.acceptable_lengths = ?");
95 }
96 if frequency.is_some() {
97 sql.push_str(" AND q.update_frequency = ?");
98 }
99 if member_id.is_some() {
100 sql.push_str(" AND q.member_id = ?");
101 }
102 let mut q = sqlx::query(&sql).bind(post_id);
103 if let Some(v) = willingness {
104 q = q.bind(v);
105 }
106 if let Some(v) = length {
107 q = q.bind(v);
108 }
109 if let Some(v) = frequency {
110 q = q.bind(v);
111 }
112 if let Some(v) = member_id {
113 q = q.bind(v);
114 }
115 let rows = q.fetch_all(&self.pool).await?;
116 Ok(rows.into_iter().map(|r| row_to_questionnaire(&r)).collect())
117 }
118
119 #[tracing::instrument(skip_all, level = "debug")]
121 pub async fn insert(&self, q: &Questionnaire) -> crate::error::ApiResult<i64> {
122 let r = sqlx::query(
123 "INSERT INTO questionnaire(member_id, willingness, acceptable_lengths, update_frequency, \
124 preferred_genres, avoid_topics, note, remark, created_at, updated_at) \
125 VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())",
126 )
127 .bind(q.member_id.unwrap_or(0))
128 .bind(q.willingness)
129 .bind(&q.acceptable_lengths)
130 .bind(q.update_frequency)
131 .bind(&q.preferred_genres)
132 .bind(&q.avoid_topics)
133 .bind(&q.note)
134 .bind(&q.remark)
135 .execute(&self.pool)
136 .await?;
137 Ok(r.last_insert_id() as i64)
138 }
139
140 #[tracing::instrument(skip_all, level = "debug")]
142 pub async fn update(&self, q: &Questionnaire) -> crate::error::ApiResult<()> {
143 sqlx::query(
144 "UPDATE questionnaire SET willingness = ?, acceptable_lengths = ?, update_frequency = ?, \
145 preferred_genres = ?, avoid_topics = ?, note = ?, remark = ?, updated_at = NOW() \
146 WHERE id = ?",
147 )
148 .bind(q.willingness)
149 .bind(&q.acceptable_lengths)
150 .bind(q.update_frequency)
151 .bind(&q.preferred_genres)
152 .bind(&q.avoid_topics)
153 .bind(&q.note)
154 .bind(&q.remark)
155 .bind(q.id)
156 .execute(&self.pool)
157 .await?;
158 Ok(())
159 }
160
161 #[tracing::instrument(skip_all, level = "debug")]
163 pub async fn select_last_assigned_time(
164 &self,
165 member_id: i32,
166 ) -> crate::error::ApiResult<Option<DateTime<Utc>>> {
167 let row = sqlx::query(
168 "SELECT MAX(med.translatorSetupTime) AS lastTime FROM mangaepisodedetail med \
169 JOIN mangaepisodetb me ON med.episodeId = me.Id \
170 WHERE me.translatorId = ? AND med.translatorSetupTime IS NOT NULL",
171 )
172 .bind(member_id)
173 .fetch_one(&self.pool)
174 .await?;
175 Ok(row.try_get("lastTime").ok())
176 }
177}
178
179fn row_to_questionnaire(row: &sqlx::mysql::MySqlRow) -> Questionnaire {
181 Questionnaire {
182 id: row.try_get("id").ok(),
183 member_id: row.try_get("member_id").ok(),
184 willingness: row.try_get("willingness").ok(),
185 acceptable_lengths: row.try_get("acceptable_lengths").ok(),
186 update_frequency: row.try_get("update_frequency").ok(),
187 preferred_genres: row.try_get("preferred_genres").ok(),
188 avoid_topics: row.try_get("avoid_topics").ok(),
189 note: row.try_get("note").ok(),
190 remark: row.try_get("remark").ok(),
191 last_assigned_time: row.try_get("last_assigned_time").ok(),
192 created_at: row.try_get("created_at").ok(),
193 updated_at: row.try_get("updated_at").ok(),
194 }
195}