tdm_server_rust/repository/
magazine_repo.rs1use crate::entity::{magazine::Magazine, manga::Manga};
6use sqlx::{MySql, Pool, Row};
7
8#[derive(Debug, Clone)]
10pub struct MagazineRow {
11 pub id: Option<i32>,
13 pub magazine_name: Option<String>,
15 pub type_: Option<i16>,
17 pub update_time: Option<String>,
19 pub price: Option<i32>,
21}
22
23pub struct MagazineRepository {
25 pool: Pool<MySql>,
27}
28
29impl MagazineRepository {
30 pub fn new(pool: Pool<MySql>) -> Self {
32 Self { pool }
33 }
34
35 #[tracing::instrument(skip_all, level = "debug")]
37 pub async fn get_magazines(
38 &self,
39 magazine_id: Option<i16>,
40 magazine_name: Option<&str>,
41 ) -> crate::error::ApiResult<Vec<MagazineRow>> {
42 let mut sql = String::from("SELECT Id, magazineName, type, updateTime, price FROM magazine WHERE 1=1");
43 if magazine_id.is_some() {
44 sql.push_str(" AND Id = ?");
45 }
46 if magazine_name.is_some() {
47 sql.push_str(" AND magazineName = ?");
48 }
49 let mut q = sqlx::query(&sql);
50 if let Some(id) = magazine_id {
51 q = q.bind(id);
52 }
53 if let Some(name) = magazine_name {
54 q = q.bind(name);
55 }
56 let rows = q.fetch_all(&self.pool).await?;
57 Ok(rows.into_iter().map(|r| row_to_magazine_row(&r)).collect())
58 }
59
60 #[tracing::instrument(skip_all, level = "debug")]
62 pub async fn delete_magazine_by_id(&self, id: i32) -> crate::error::ApiResult<()> {
63 sqlx::query("DELETE FROM magazine WHERE Id = ?")
64 .bind(id)
65 .execute(&self.pool)
66 .await?;
67 Ok(())
68 }
69
70 #[tracing::instrument(skip_all, level = "debug")]
72 pub async fn insert_magazine(&self, row: &MagazineRow) -> crate::error::ApiResult<i32> {
73 let r = sqlx::query(
74 "INSERT INTO magazine(magazineName, type, updateTime, price) VALUES (?, ?, ?, ?)",
75 )
76 .bind(&row.magazine_name)
77 .bind(row.type_)
78 .bind(&row.update_time)
79 .bind(row.price)
80 .execute(&self.pool)
81 .await?;
82 Ok(r.last_insert_id() as i32)
83 }
84
85 #[tracing::instrument(skip_all, level = "debug")]
87 pub async fn get_magazine_by_id(&self, id: i32) -> crate::error::ApiResult<Option<MagazineRow>> {
88 let row = sqlx::query(
89 "SELECT Id, magazineName, type, updateTime, price FROM magazine WHERE Id = ?",
90 )
91 .bind(id)
92 .fetch_optional(&self.pool)
93 .await?;
94 Ok(row.map(|r| row_to_magazine_row(&r)))
95 }
96
97 #[tracing::instrument(skip_all, level = "debug")]
99 pub async fn update_magazine(&self, row: &MagazineRow) -> crate::error::ApiResult<()> {
100 sqlx::query(
101 "UPDATE magazine SET type = COALESCE(?, type), magazineName = COALESCE(?, magazineName), \
102 updateTime = COALESCE(?, updateTime), price = COALESCE(?, price) WHERE Id = ?",
103 )
104 .bind(row.type_)
105 .bind(&row.magazine_name)
106 .bind(&row.update_time)
107 .bind(row.price)
108 .bind(row.id)
109 .execute(&self.pool)
110 .await?;
111 Ok(())
112 }
113
114 #[tracing::instrument(skip_all, level = "debug")]
116 pub async fn test_magazine_name(&self, magazine_name: &str) -> crate::error::ApiResult<Option<MagazineRow>> {
117 let row = sqlx::query(
118 "SELECT Id, magazineName, type, updateTime, price FROM magazine WHERE magazineName = ?",
119 )
120 .bind(magazine_name)
121 .fetch_optional(&self.pool)
122 .await?;
123 Ok(row.map(|r| row_to_magazine_row(&r)))
124 }
125
126 #[tracing::instrument(skip_all, level = "debug")]
128 pub async fn get_related_magazine(&self, id: i32) -> crate::error::ApiResult<bool> {
129 let row = sqlx::query("SELECT magazineId FROM mangamagazine WHERE magazineId = ? LIMIT 1")
130 .bind(id)
131 .fetch_optional(&self.pool)
132 .await?;
133 Ok(row.is_some())
134 }
135
136 #[tracing::instrument(skip_all, level = "debug")]
138 pub async fn get_max_magazine_id(&self) -> crate::error::ApiResult<Option<i32>> {
139 let row = sqlx::query("SELECT MAX(Id) AS maxId FROM magazine")
140 .fetch_one(&self.pool)
141 .await?;
142 Ok(row.try_get("maxId").ok())
143 }
144
145 #[tracing::instrument(skip_all, level = "debug")]
147 pub async fn get_manga_magazine_list(&self) -> crate::error::ApiResult<Vec<MagazineRow>> {
148 let rows = sqlx::query("SELECT Id, magazineName, type, updateTime, price FROM magazine")
149 .fetch_all(&self.pool)
150 .await?;
151 Ok(rows.into_iter().map(|r| row_to_magazine_row(&r)).collect())
152 }
153
154 #[tracing::instrument(skip_all, level = "debug")]
156 pub async fn get_magazine_manga(&self, id: i32) -> crate::error::ApiResult<Vec<Manga>> {
157 let rows = sqlx::query(
158 "SELECT DISTINCT m.Id, m.mangaTranName, m.mangaOriName, m.category, m.mangaStatus, \
159 m.image AS imgUrl, m.updateTime \
160 FROM mangatb m \
161 LEFT JOIN mangamagazine mm ON m.Id = mm.mangaId \
162 LEFT JOIN magazine maga ON mm.magazineId = maga.Id \
163 WHERE maga.Id = ? \
164 GROUP BY m.Id, m.updateTime \
165 ORDER BY m.updateTime DESC",
166 )
167 .bind(id)
168 .fetch_all(&self.pool)
169 .await?;
170 Ok(rows.into_iter().map(|r| row_to_manga(&r)).collect())
171 }
172
173 pub fn to_entity(row: &MagazineRow) -> Magazine {
175 Magazine {
176 id: row.id,
177 magazine_name: row.magazine_name.clone(),
178 r#type: row.type_,
179 update_time: row.update_time.clone(),
180 price: row.price,
181 }
182 }
183}
184
185fn row_to_magazine_row(row: &sqlx::mysql::MySqlRow) -> MagazineRow {
187 MagazineRow {
188 id: row.try_get("Id").ok(),
189 magazine_name: row.try_get("magazineName").ok(),
190 type_: row.try_get("type").ok(),
191 update_time: row.try_get("updateTime").ok(),
192 price: row.try_get("price").ok(),
193 }
194}
195
196fn row_to_manga(row: &sqlx::mysql::MySqlRow) -> Manga {
198 use chrono::{DateTime, Utc};
199 Manga {
200 id: row.try_get("Id").ok(),
201 manga_tran_name: row.try_get("mangaTranName").ok(),
202 manga_ori_name: row.try_get("mangaOriName").ok(),
203 category: row.try_get("category").ok(),
204 manga_status: row.try_get("mangaStatus").ok(),
205 img_url: row.try_get("imgUrl").ok(),
206 link: None,
207 introduction: None,
208 update_time: row.try_get::<DateTime<Utc>, _>("updateTime").ok(),
209 }
210}