Skip to main content

tdm_server_rust/repository/
author_repo.rs

1//! 作者数据访问层 (Author Repository)
2//!
3//! 封装 `authortb` 表的增删改查(SeaORM)。
4
5use crate::db::DbConn;
6use crate::entity::{author::Author, manga::Manga};
7use crate::sea_entity::{authortb, mangaauthor, mangatb};
8use sea_orm::{
9    ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, JoinType, PaginatorTrait,
10    QueryFilter, QueryOrder, QuerySelect, RelationTrait, Set,
11};
12use sqlx::postgres::PgPool;
13
14/// 作者仓储
15pub struct AuthorRepository {
16    /// SeaORM 数据库连接
17    db: DbConn,
18}
19
20impl AuthorRepository {
21    /// 从 `PgPool` 构造(桥接 SeaORM,兼容现有 `AppState`)
22    pub fn new(pool: PgPool) -> Self {
23        Self {
24            db: crate::db::from_sqlx_pool(pool),
25        }
26    }
27
28    /// 从 `DatabaseConnection` 构造
29    pub fn from_db(db: DatabaseConnection) -> Self {
30        Self { db }
31    }
32
33    /// 条件查询作者列表
34    #[tracing::instrument(skip_all, level = "debug")]
35    pub async fn get_authors(
36        &self,
37        author_id: Option<i16>,
38        author_name: Option<&str>,
39    ) -> crate::error::ApiResult<Vec<Author>> {
40        let mut q = authortb::Entity::find();
41        if let Some(id) = author_id {
42            q = q.filter(authortb::Column::Id.eq(id as i32));
43        }
44        if let Some(name) = author_name {
45            q = q.filter(authortb::Column::AuthorName.eq(name));
46        }
47        let rows = q.all(&self.db).await?;
48        Ok(rows.into_iter().map(model_to_author).collect())
49    }
50
51    /// 按 ID 删除作者
52    #[tracing::instrument(skip_all, level = "debug")]
53    pub async fn delete_by_id(&self, id: i32) -> crate::error::ApiResult<()> {
54        authortb::Entity::delete_by_id(id).exec(&self.db).await?;
55        Ok(())
56    }
57
58    /// 新增作者
59    #[tracing::instrument(skip_all, level = "debug")]
60    pub async fn insert(&self, author: &Author) -> crate::error::ApiResult<i32> {
61        let name = author
62            .author_name
63            .as_deref()
64            .ok_or_else(|| crate::error::AppError::business("作者名不能为空"))?;
65        let model = authortb::ActiveModel {
66            author_name: Set(name.to_string()),
67            ..Default::default()
68        };
69        let inserted = model.insert(&self.db).await?;
70        Ok(inserted.id)
71    }
72
73    /// 按 ID 查询作者
74    #[tracing::instrument(skip_all, level = "debug")]
75    pub async fn get_author_by_id(&self, id: i32) -> crate::error::ApiResult<Option<Author>> {
76        let row = authortb::Entity::find_by_id(id).one(&self.db).await?;
77        Ok(row.map(model_to_author))
78    }
79
80    /// 更新作者
81    #[tracing::instrument(skip_all, level = "debug")]
82    pub async fn update_author(&self, author: &Author) -> crate::error::ApiResult<()> {
83        let id = author
84            .id
85            .ok_or_else(|| crate::error::AppError::business("作者 ID 不能为空"))?;
86        let name = author
87            .author_name
88            .as_deref()
89            .ok_or_else(|| crate::error::AppError::business("作者名不能为空"))?;
90        let model = authortb::ActiveModel {
91            id: Set(id),
92            author_name: Set(name.to_string()),
93        };
94        model.update(&self.db).await?;
95        Ok(())
96    }
97
98    /// 按名称检测作者是否已存在
99    #[tracing::instrument(skip_all, level = "debug")]
100    pub async fn test_author_name(
101        &self,
102        author_name: &str,
103    ) -> crate::error::ApiResult<Option<Author>> {
104        let row = authortb::Entity::find()
105            .filter(authortb::Column::AuthorName.eq(author_name))
106            .one(&self.db)
107            .await?;
108        Ok(row.map(model_to_author))
109    }
110
111    /// 删除前检查是否绑定漫画
112    #[tracing::instrument(skip_all, level = "debug")]
113    pub async fn get_related_manga(&self, id: i32) -> crate::error::ApiResult<bool> {
114        let n = mangaauthor::Entity::find()
115            .filter(mangaauthor::Column::AuthorId.eq(id))
116            .count(&self.db)
117            .await?;
118        Ok(n > 0)
119    }
120
121    /// 获取最大作者 ID
122    #[tracing::instrument(skip_all, level = "debug")]
123    pub async fn get_max_author_id(&self) -> crate::error::ApiResult<Option<i32>> {
124        let row = authortb::Entity::find()
125            .order_by_desc(authortb::Column::Id)
126            .one(&self.db)
127            .await?;
128        Ok(row.map(|r| r.id))
129    }
130
131    /// 无条件查询全部作者
132    #[tracing::instrument(skip_all, level = "debug")]
133    pub async fn get_manga_author_list(&self) -> crate::error::ApiResult<Vec<Author>> {
134        let rows = authortb::Entity::find().all(&self.db).await?;
135        Ok(rows.into_iter().map(model_to_author).collect())
136    }
137
138    /// 查询作者关联的全部漫画
139    #[tracing::instrument(skip_all, level = "debug")]
140    pub async fn get_author_manga(&self, id: i32) -> crate::error::ApiResult<Vec<Manga>> {
141        let rows = mangatb::Entity::find()
142            .join(
143                JoinType::InnerJoin,
144                mangaauthor::Relation::Mangatb.def().rev(),
145            )
146            .filter(mangaauthor::Column::AuthorId.eq(id))
147            .distinct()
148            .order_by_desc(mangatb::Column::UpdateTime)
149            .all(&self.db)
150            .await?;
151        Ok(rows.into_iter().map(model_to_manga).collect())
152    }
153}
154
155/// SeaORM Model 映射为 API 作者
156fn model_to_author(m: authortb::Model) -> Author {
157    Author {
158        id: Some(m.id),
159        author_name: Some(m.author_name),
160    }
161}
162
163/// SeaORM Model 映射为漫画 POJO
164fn model_to_manga(m: mangatb::Model) -> Manga {
165    Manga {
166        id: Some(m.id),
167        manga_tran_name: Some(m.manga_tran_name),
168        manga_ori_name: Some(m.manga_ori_name),
169        category: Some(m.category as i16),
170        manga_status: Some(m.manga_status as i16),
171        img_url: Some(m.image),
172        link: m.link,
173        introduction: m.introduction,
174        update_time: Some(m.update_time.and_utc()),
175    }
176}