tdm_server_rust/repository/
manga_benefit_repo.rs1use crate::db::DbConn;
6use crate::sea_entity::manga_benefit;
7use chrono::{DateTime, Utc};
8use sea_orm::{
9 ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, QueryOrder, Set,
10};
11use sqlx::postgres::PgPool;
12
13#[derive(Debug, Clone)]
15pub struct BenefitRow {
16 pub id: i32,
18 pub manga_id: i32,
20 pub volume_number: i32,
22 pub volume_title: Option<String>,
24 pub store_name: Option<String>,
26 pub benefit_name: Option<String>,
28 pub benefit_tag: Option<String>,
30 pub img_url: Option<String>,
32 pub r#type: Option<i16>,
34 pub publish_time: Option<DateTime<Utc>>,
36}
37
38#[derive(Debug, Clone)]
40pub struct BenefitUpsert {
41 pub manga_id: i32,
43 pub volume_number: i32,
45 pub volume_title: Option<String>,
47 pub store_name: Option<String>,
49 pub benefit_name: Option<String>,
51 pub benefit_tag: Option<String>,
53 pub r#type: Option<i16>,
55 pub img_url: Option<String>,
57 pub publish_time: Option<DateTime<Utc>>,
59}
60
61pub struct MangaBenefitRepository {
63 db: DbConn,
65}
66
67impl MangaBenefitRepository {
68 pub fn new(pool: PgPool) -> Self {
70 Self {
71 db: crate::db::from_sqlx_pool(pool),
72 }
73 }
74
75 pub fn from_db(db: DatabaseConnection) -> Self {
77 Self { db }
78 }
79
80 #[tracing::instrument(skip_all, level = "debug")]
82 pub async fn list_by_manga_id(
83 &self,
84 manga_id: i32,
85 ) -> crate::error::ApiResult<Vec<BenefitRow>> {
86 let rows = manga_benefit::Entity::find()
87 .filter(manga_benefit::Column::MangaId.eq(manga_id))
88 .filter(manga_benefit::Column::DeletedAt.is_null())
89 .order_by_asc(manga_benefit::Column::VolumeNumber)
90 .order_by_asc(manga_benefit::Column::Id)
91 .all(&self.db)
92 .await?;
93 Ok(rows.into_iter().map(model_to_row).collect())
94 }
95
96 #[tracing::instrument(skip_all, level = "debug")]
98 pub async fn get_by_id(&self, id: i32) -> crate::error::ApiResult<Option<BenefitRow>> {
99 let row = manga_benefit::Entity::find_by_id(id)
100 .filter(manga_benefit::Column::DeletedAt.is_null())
101 .one(&self.db)
102 .await?;
103 Ok(row.map(model_to_row))
104 }
105
106 #[tracing::instrument(skip_all, level = "debug")]
108 pub async fn insert(&self, input: &BenefitUpsert) -> crate::error::ApiResult<i32> {
109 let now = chrono::Utc::now().naive_utc();
110 let model = manga_benefit::ActiveModel {
111 manga_id: Set(input.manga_id),
112 volume_number: Set(input.volume_number),
113 volume_title: Set(input.volume_title.clone()),
114 store_name: Set(input.store_name.clone()),
115 benefit_name: Set(input.benefit_name.clone()),
116 benefit_tag: Set(input.benefit_tag.clone()),
117 r#type: Set(input.r#type),
118 img_url: Set(input.img_url.clone()),
119 publish_time: Set(input.publish_time.map(|t| t.naive_utc())),
120 created_at: Set(Some(now)),
121 updated_at: Set(Some(now)),
122 deleted_at: Set(None),
123 ..Default::default()
124 };
125 let inserted = model.insert(&self.db).await?;
126 Ok(inserted.id)
127 }
128
129 #[tracing::instrument(skip_all, level = "debug")]
131 pub async fn update(&self, id: i32, input: &BenefitUpsert) -> crate::error::ApiResult<()> {
132 let existing = manga_benefit::Entity::find_by_id(id)
133 .filter(manga_benefit::Column::DeletedAt.is_null())
134 .one(&self.db)
135 .await?
136 .ok_or_else(|| crate::error::AppError::business("要更新的特典不存在"))?;
137 let mut am: manga_benefit::ActiveModel = existing.into();
138 am.manga_id = Set(input.manga_id);
139 am.volume_number = Set(input.volume_number);
140 am.volume_title = Set(input.volume_title.clone());
141 am.store_name = Set(input.store_name.clone());
142 am.benefit_name = Set(input.benefit_name.clone());
143 am.benefit_tag = Set(input.benefit_tag.clone());
144 am.r#type = Set(input.r#type);
145 am.img_url = Set(input.img_url.clone());
146 am.publish_time = Set(input.publish_time.map(|t| t.naive_utc()));
147 am.updated_at = Set(Some(chrono::Utc::now().naive_utc()));
148 am.update(&self.db).await?;
149 Ok(())
150 }
151
152 #[tracing::instrument(skip_all, level = "debug")]
154 pub async fn soft_delete(&self, id: i32) -> crate::error::ApiResult<()> {
155 let existing = manga_benefit::Entity::find_by_id(id)
156 .filter(manga_benefit::Column::DeletedAt.is_null())
157 .one(&self.db)
158 .await?
159 .ok_or_else(|| crate::error::AppError::business("特典不存在"))?;
160 let mut am: manga_benefit::ActiveModel = existing.into();
161 am.deleted_at = Set(Some(chrono::Utc::now().naive_utc()));
162 am.updated_at = Set(Some(chrono::Utc::now().naive_utc()));
163 am.update(&self.db).await?;
164 Ok(())
165 }
166}
167
168fn model_to_row(m: manga_benefit::Model) -> BenefitRow {
170 BenefitRow {
171 id: m.id,
172 manga_id: m.manga_id,
173 volume_number: m.volume_number,
174 volume_title: m.volume_title,
175 store_name: m.store_name,
176 benefit_name: m.benefit_name,
177 benefit_tag: m.benefit_tag,
178 img_url: m.img_url,
179 r#type: m.r#type,
180 publish_time: m.publish_time.map(|t| t.and_utc()),
181 }
182}