tdm_server_rust/repository/
author_repo.rs1use crate::entity::{author::Author, manga::Manga};
6use sqlx::{MySql, Pool, Row};
7
8pub struct AuthorRepository {
10 pool: Pool<MySql>,
12}
13
14impl AuthorRepository {
15 pub fn new(pool: Pool<MySql>) -> Self {
17 Self { pool }
18 }
19
20 #[tracing::instrument(skip_all, level = "debug")]
22 pub async fn get_authors(
23 &self,
24 author_id: Option<i16>,
25 author_name: Option<&str>,
26 ) -> crate::error::ApiResult<Vec<Author>> {
27 let mut sql = String::from("SELECT a.Id, a.authorName FROM authortb a WHERE 1=1");
28 if author_id.is_some() {
29 sql.push_str(" AND a.Id = ?");
30 }
31 if author_name.is_some() {
32 sql.push_str(" AND a.authorName = ?");
33 }
34 let mut q = sqlx::query(&sql);
35 if let Some(id) = author_id {
36 q = q.bind(id);
37 }
38 if let Some(name) = author_name {
39 q = q.bind(name);
40 }
41 let rows = q.fetch_all(&self.pool).await?;
42 Ok(rows.into_iter().map(|r| row_to_author(&r)).collect())
43 }
44
45 #[tracing::instrument(skip_all, level = "debug")]
47 pub async fn delete_by_id(&self, id: i32) -> crate::error::ApiResult<()> {
48 sqlx::query("DELETE FROM authortb WHERE Id = ?")
49 .bind(id)
50 .execute(&self.pool)
51 .await?;
52 Ok(())
53 }
54
55 #[tracing::instrument(skip_all, level = "debug")]
57 pub async fn insert(&self, author: &Author) -> crate::error::ApiResult<i32> {
58 let r = sqlx::query("INSERT INTO authortb(authorName) VALUES (?)")
59 .bind(&author.author_name)
60 .execute(&self.pool)
61 .await?;
62 Ok(r.last_insert_id() as i32)
63 }
64
65 #[tracing::instrument(skip_all, level = "debug")]
67 pub async fn get_author_by_id(&self, id: i32) -> crate::error::ApiResult<Option<Author>> {
68 let row = sqlx::query("SELECT Id, authorName FROM authortb WHERE Id = ?")
69 .bind(id)
70 .fetch_optional(&self.pool)
71 .await?;
72 Ok(row.map(|r| row_to_author(&r)))
73 }
74
75 #[tracing::instrument(skip_all, level = "debug")]
77 pub async fn update_author(&self, author: &Author) -> crate::error::ApiResult<()> {
78 sqlx::query("UPDATE authortb SET authorName = ? WHERE Id = ?")
79 .bind(&author.author_name)
80 .bind(author.id)
81 .execute(&self.pool)
82 .await?;
83 Ok(())
84 }
85
86 #[tracing::instrument(skip_all, level = "debug")]
88 pub async fn test_author_name(&self, author_name: &str) -> crate::error::ApiResult<Option<Author>> {
89 let row = sqlx::query("SELECT Id, authorName FROM authortb WHERE authorName = ?")
90 .bind(author_name)
91 .fetch_optional(&self.pool)
92 .await?;
93 Ok(row.map(|r| row_to_author(&r)))
94 }
95
96 #[tracing::instrument(skip_all, level = "debug")]
98 pub async fn get_related_manga(&self, id: i32) -> crate::error::ApiResult<bool> {
99 let row = sqlx::query("SELECT authorId FROM mangaauthor WHERE authorId = ? LIMIT 1")
100 .bind(id)
101 .fetch_optional(&self.pool)
102 .await?;
103 Ok(row.is_some())
104 }
105
106 #[tracing::instrument(skip_all, level = "debug")]
108 pub async fn get_max_author_id(&self) -> crate::error::ApiResult<Option<i32>> {
109 let row = sqlx::query("SELECT MAX(Id) AS maxId FROM authortb")
110 .fetch_one(&self.pool)
111 .await?;
112 Ok(row.try_get("maxId").ok())
113 }
114
115 #[tracing::instrument(skip_all, level = "debug")]
117 pub async fn get_manga_author_list(&self) -> crate::error::ApiResult<Vec<Author>> {
118 let rows = sqlx::query("SELECT Id, authorName FROM authortb")
119 .fetch_all(&self.pool)
120 .await?;
121 Ok(rows.into_iter().map(|r| row_to_author(&r)).collect())
122 }
123
124 #[tracing::instrument(skip_all, level = "debug")]
126 pub async fn get_author_manga(&self, id: i32) -> crate::error::ApiResult<Vec<Manga>> {
127 let rows = sqlx::query(
128 "SELECT DISTINCT m.Id, m.mangaTranName, m.mangaOriName, m.category, m.mangaStatus, \
129 m.image AS imgUrl, m.updateTime \
130 FROM mangatb m \
131 LEFT JOIN mangaauthor ma ON m.Id = ma.mangaId \
132 LEFT JOIN authortb a ON ma.authorId = a.Id \
133 WHERE a.Id = ? \
134 GROUP BY m.Id, m.updateTime \
135 ORDER BY m.updateTime DESC",
136 )
137 .bind(id)
138 .fetch_all(&self.pool)
139 .await?;
140 Ok(rows.into_iter().map(|r| row_to_manga(&r)).collect())
141 }
142}
143
144fn row_to_author(row: &sqlx::mysql::MySqlRow) -> Author {
146 Author {
147 id: row.try_get("Id").ok(),
148 author_name: row.try_get("authorName").ok(),
149 }
150}
151
152fn row_to_manga(row: &sqlx::mysql::MySqlRow) -> Manga {
154 use chrono::{DateTime, Utc};
155 Manga {
156 id: row.try_get("Id").ok(),
157 manga_tran_name: row.try_get("mangaTranName").ok(),
158 manga_ori_name: row.try_get("mangaOriName").ok(),
159 category: row.try_get("category").ok(),
160 manga_status: row.try_get("mangaStatus").ok(),
161 img_url: row.try_get("imgUrl").ok(),
162 link: None,
163 introduction: None,
164 update_time: row.try_get::<DateTime<Utc>, _>("updateTime").ok(),
165 }
166}