tdm_server_rust/repository/
magazine_repo.rs1use crate::db::DbConn;
6use crate::entity::{magazine::Magazine, manga::Manga};
7use crate::sea_entity::{magazine, mangamagazine, mangatb};
8use sea_orm::{
9 ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, JoinType, PaginatorTrait,
10 QueryFilter, QueryOrder, QuerySelect, RelationTrait, Set,
11};
12use sqlx::postgres::PgPool;
13
14#[derive(Debug, Clone)]
16pub struct MagazineRow {
17 pub id: Option<i32>,
19 pub magazine_name: Option<String>,
21 pub type_: Option<i16>,
23 pub update_time: Option<String>,
25 pub price: Option<i32>,
27}
28
29pub struct MagazineRepository {
31 db: DbConn,
33}
34
35impl MagazineRepository {
36 pub fn new(pool: PgPool) -> Self {
38 Self {
39 db: crate::db::from_sqlx_pool(pool),
40 }
41 }
42
43 pub fn from_db(db: DatabaseConnection) -> Self {
45 Self { db }
46 }
47
48 #[tracing::instrument(skip_all, level = "debug")]
50 pub async fn get_magazines(
51 &self,
52 magazine_id: Option<i16>,
53 magazine_name: Option<&str>,
54 ) -> crate::error::ApiResult<Vec<MagazineRow>> {
55 let mut q = magazine::Entity::find();
56 if let Some(id) = magazine_id {
57 q = q.filter(magazine::Column::Id.eq(id as i32));
58 }
59 if let Some(name) = magazine_name {
60 q = q.filter(magazine::Column::MagazineName.eq(name));
61 }
62 let rows = q.all(&self.db).await?;
63 Ok(rows.into_iter().map(model_to_magazine_row).collect())
64 }
65
66 #[tracing::instrument(skip_all, level = "debug")]
68 pub async fn delete_magazine_by_id(&self, id: i32) -> crate::error::ApiResult<()> {
69 magazine::Entity::delete_by_id(id).exec(&self.db).await?;
70 Ok(())
71 }
72
73 #[tracing::instrument(skip_all, level = "debug")]
75 pub async fn insert_magazine(&self, row: &MagazineRow) -> crate::error::ApiResult<i32> {
76 let name = row
77 .magazine_name
78 .as_deref()
79 .ok_or_else(|| crate::error::AppError::business("杂志名不能为空"))?;
80 let model = magazine::ActiveModel {
81 magazine_name: Set(name.to_string()),
82 r#type: Set(row.type_.map(|v| v as i32)),
83 update_time: Set(row.update_time.clone()),
84 price: Set(row.price),
85 ..Default::default()
86 };
87 let inserted = model.insert(&self.db).await?;
88 Ok(inserted.id)
89 }
90
91 #[tracing::instrument(skip_all, level = "debug")]
93 pub async fn get_magazine_by_id(
94 &self,
95 id: i32,
96 ) -> crate::error::ApiResult<Option<MagazineRow>> {
97 let row = magazine::Entity::find_by_id(id).one(&self.db).await?;
98 Ok(row.map(model_to_magazine_row))
99 }
100
101 #[tracing::instrument(skip_all, level = "debug")]
103 pub async fn update_magazine(&self, row: &MagazineRow) -> crate::error::ApiResult<()> {
104 let id = row
105 .id
106 .ok_or_else(|| crate::error::AppError::business("杂志 ID 不能为空"))?;
107 let existing = magazine::Entity::find_by_id(id)
108 .one(&self.db)
109 .await?
110 .ok_or_else(|| crate::error::AppError::business("杂志不存在"))?;
111 let mut am: magazine::ActiveModel = existing.into();
112 if let Some(t) = row.type_ {
113 am.r#type = Set(Some(t as i32));
114 }
115 if let Some(ref name) = row.magazine_name {
116 am.magazine_name = Set(name.clone());
117 }
118 if let Some(ref ut) = row.update_time {
119 am.update_time = Set(Some(ut.clone()));
120 }
121 if let Some(p) = row.price {
122 am.price = Set(Some(p));
123 }
124 am.update(&self.db).await?;
125 Ok(())
126 }
127
128 #[tracing::instrument(skip_all, level = "debug")]
130 pub async fn test_magazine_name(
131 &self,
132 magazine_name: &str,
133 ) -> crate::error::ApiResult<Option<MagazineRow>> {
134 let row = magazine::Entity::find()
135 .filter(magazine::Column::MagazineName.eq(magazine_name))
136 .one(&self.db)
137 .await?;
138 Ok(row.map(model_to_magazine_row))
139 }
140
141 #[tracing::instrument(skip_all, level = "debug")]
143 pub async fn get_related_magazine(&self, id: i32) -> crate::error::ApiResult<bool> {
144 let n = mangamagazine::Entity::find()
145 .filter(mangamagazine::Column::MagazineId.eq(id))
146 .count(&self.db)
147 .await?;
148 Ok(n > 0)
149 }
150
151 #[tracing::instrument(skip_all, level = "debug")]
153 pub async fn get_max_magazine_id(&self) -> crate::error::ApiResult<Option<i32>> {
154 let row = magazine::Entity::find()
155 .order_by_desc(magazine::Column::Id)
156 .one(&self.db)
157 .await?;
158 Ok(row.map(|r| r.id))
159 }
160
161 #[tracing::instrument(skip_all, level = "debug")]
163 pub async fn get_manga_magazine_list(&self) -> crate::error::ApiResult<Vec<MagazineRow>> {
164 let rows = magazine::Entity::find().all(&self.db).await?;
165 Ok(rows.into_iter().map(model_to_magazine_row).collect())
166 }
167
168 #[tracing::instrument(skip_all, level = "debug")]
170 pub async fn get_magazine_manga(&self, id: i32) -> crate::error::ApiResult<Vec<Manga>> {
171 let rows = mangatb::Entity::find()
172 .join(
173 JoinType::InnerJoin,
174 mangamagazine::Relation::Mangatb.def().rev(),
175 )
176 .filter(mangamagazine::Column::MagazineId.eq(id))
177 .distinct()
178 .order_by_desc(mangatb::Column::UpdateTime)
179 .all(&self.db)
180 .await?;
181 Ok(rows.into_iter().map(model_to_manga).collect())
182 }
183
184 pub fn to_entity(row: &MagazineRow) -> Magazine {
186 Magazine {
187 id: row.id,
188 magazine_name: row.magazine_name.clone(),
189 r#type: row.type_,
190 update_time: row.update_time.clone(),
191 price: row.price,
192 }
193 }
194}
195
196fn model_to_magazine_row(m: magazine::Model) -> MagazineRow {
198 MagazineRow {
199 id: Some(m.id),
200 magazine_name: Some(m.magazine_name),
201 type_: m.r#type.map(|v| v as i16),
202 update_time: m.update_time,
203 price: m.price,
204 }
205}
206
207fn model_to_manga(m: mangatb::Model) -> Manga {
209 Manga {
210 id: Some(m.id),
211 manga_tran_name: Some(m.manga_tran_name),
212 manga_ori_name: Some(m.manga_ori_name),
213 category: Some(m.category as i16),
214 manga_status: Some(m.manga_status as i16),
215 img_url: Some(m.image),
216 link: m.link,
217 introduction: m.introduction,
218 update_time: Some(m.update_time.and_utc()),
219 }
220}