Skip to main content

tdm_server_rust/service/
author_service.rs

1//! 作者业务服务 (Author Service)
2//!
3//! 作者信息的增删改查及关联漫画查询。
4
5use crate::{
6    app::AppState,
7    cache::on_author_or_magazine_renamed,
8    common::PageBean,
9    entity::{author::Author, manga::MangaListVo},
10    error::{ApiResult, AppError},
11    repository::{author_repo::AuthorRepository, manga_repo::MangaRepository},
12    utils::page::{paginate, slice_rows},
13};
14
15/// 作者服务
16pub struct AuthorService;
17
18impl AuthorService {
19    /// 分页查询作者
20    #[tracing::instrument(skip_all, level = "debug")]
21    pub async fn get_authors(
22        state: &AppState,
23        page: i32,
24        page_size: i32,
25        author_id: Option<i16>,
26        author_name: Option<String>,
27    ) -> ApiResult<PageBean<Author>> {
28        let repo = AuthorRepository::new(state.db.clone());
29        let all = repo.get_authors(author_id, author_name.as_deref()).await?;
30        Ok(paginate(all, page, page_size))
31    }
32
33    /// 全量作者列表
34    #[tracing::instrument(skip_all, level = "debug")]
35    pub async fn get_manga_author_list(state: &AppState) -> ApiResult<Vec<Author>> {
36        AuthorRepository::new(state.db.clone())
37            .get_manga_author_list()
38            .await
39    }
40
41    /// 查询作者所著漫画
42    #[tracing::instrument(skip_all, level = "debug")]
43    pub async fn get_author_manga(
44        state: &AppState,
45        page: i32,
46        page_size: i32,
47        id: i32,
48    ) -> ApiResult<PageBean<MangaListVo>> {
49        let (total, rows) = MangaRepository::new(state.db.clone())
50            .list_by_author_page(id, page, page_size)
51            .await?;
52        Ok(slice_rows(rows, total))
53    }
54
55    /// 删除作者
56    #[tracing::instrument(skip_all, level = "debug")]
57    pub async fn delete(state: &AppState, id: i32) -> ApiResult<()> {
58        let repo = AuthorRepository::new(state.db.clone());
59        if repo.get_related_manga(id).await? {
60            return Err(AppError::business("该作者已经绑定漫画了喵!"));
61        }
62        repo.delete_by_id(id).await
63    }
64
65    /// 新增作者
66    #[tracing::instrument(skip_all, level = "debug")]
67    pub async fn add(state: &AppState, author: Author) -> ApiResult<()> {
68        let repo = AuthorRepository::new(state.db.clone());
69        if let Some(name) = &author.author_name {
70            if repo.test_author_name(name).await?.is_some() {
71                return Err(AppError::unique("作者名"));
72            }
73        }
74        repo.insert(&author).await?;
75        Ok(())
76    }
77
78    /// 按 ID 查询作者
79    #[tracing::instrument(skip_all, level = "debug")]
80    pub async fn get_author_by_id(state: &AppState, id: i32) -> ApiResult<Author> {
81        AuthorRepository::new(state.db.clone())
82            .get_author_by_id(id)
83            .await?
84            .ok_or_else(|| AppError::business("作者不存在喵"))
85    }
86
87    /// 更新作者
88    #[tracing::instrument(skip_all, level = "debug")]
89    pub async fn update_author(state: &AppState, author: Author) -> ApiResult<()> {
90        let id = author.id.ok_or_else(|| AppError::business("缺少作者 ID"))?;
91        let repo = AuthorRepository::new(state.db.clone());
92        repo.get_author_by_id(id)
93            .await?
94            .ok_or_else(|| AppError::business("作者不存在喵"))?;
95        if let Some(name) = &author.author_name {
96            if let Some(existing) = repo.test_author_name(name).await? {
97                if existing.id != Some(id) {
98                    return Err(AppError::unique("作者名"));
99                }
100            }
101        }
102        repo.update_author(&author).await?;
103        on_author_or_magazine_renamed(state).await;
104        Ok(())
105    }
106}