tdm_server_rust/repository/
editor_unit_repo.rs1use crate::db::DbConn;
7use crate::entity::editor::EditorUnitInput;
8use crate::error::ApiResult;
9use crate::sea_entity::editor_unit;
10use sea_orm::{
11 ColumnTrait, ConnectionTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter,
12 QueryOrder, Set, TransactionTrait,
13};
14use sqlx::postgres::PgPool;
15
16pub struct EditorUnitRepository {
18 db: DbConn,
20}
21
22impl EditorUnitRepository {
23 pub fn new(pool: PgPool) -> Self {
25 Self {
26 db: crate::db::from_sqlx_pool(pool),
27 }
28 }
29
30 pub fn from_db(db: DatabaseConnection) -> Self {
32 Self { db }
33 }
34
35 #[tracing::instrument(skip_all, level = "debug")]
37 pub async fn list_by_episode(&self, episode_id: i32) -> ApiResult<Vec<editor_unit::Model>> {
38 let rows = editor_unit::Entity::find()
39 .filter(editor_unit::Column::EpisodeId.eq(episode_id))
40 .order_by_asc(editor_unit::Column::PageId)
41 .order_by_asc(editor_unit::Column::UnitIndex)
42 .all(&self.db)
43 .await?;
44 Ok(rows)
45 }
46
47 #[tracing::instrument(skip_all, level = "debug")]
49 pub async fn list_by_page(
50 &self,
51 episode_id: i32,
52 page_id: i64,
53 ) -> ApiResult<Vec<editor_unit::Model>> {
54 let rows = editor_unit::Entity::find()
55 .filter(editor_unit::Column::EpisodeId.eq(episode_id))
56 .filter(editor_unit::Column::PageId.eq(page_id))
57 .order_by_asc(editor_unit::Column::UnitIndex)
58 .all(&self.db)
59 .await?;
60 Ok(rows)
61 }
62
63 #[tracing::instrument(skip_all, level = "debug")]
65 pub async fn replace_page_units(
66 &self,
67 episode_id: i32,
68 page_id: i64,
69 editor_member_id: i32,
70 units: &[EditorUnitInput],
71 ) -> ApiResult<usize> {
72 let txn = self.db.begin().await?;
73 editor_unit::Entity::delete_many()
74 .filter(editor_unit::Column::EpisodeId.eq(episode_id))
75 .filter(editor_unit::Column::PageId.eq(page_id))
76 .exec(&txn)
77 .await?;
78 if !units.is_empty() {
79 let now = chrono::Utc::now().naive_utc();
80 let models: Vec<editor_unit::ActiveModel> = units
81 .iter()
82 .map(|u| editor_unit::ActiveModel {
83 episode_id: Set(episode_id),
84 page_id: Set(page_id),
85 unit_index: Set(u.index),
86 x_coord: Set(u.x_coord),
87 y_coord: Set(u.y_coord),
88 in_bubble: Set(u.in_bubble),
89 is_proofread: Set(u.is_proofread),
90 translated_text: Set(u.translated_text.clone()),
91 translator_id: Set(u.translator_id),
92 translator_comment: Set(u.translator_comment.clone()),
93 proofreader_text: Set(u.proofreader_text.clone()),
94 proofreader_id: Set(u.proofreader_id),
95 proofreader_comment: Set(u.proofreader_comment.clone()),
96 last_edited_by: Set(Some(editor_member_id)),
97 last_edited_at: Set(Some(now)),
98 ..Default::default()
99 })
100 .collect();
101 editor_unit::Entity::insert_many(models).exec(&txn).await?;
102 }
103 txn.commit().await?;
104 Ok(units.len())
105 }
106
107 #[tracing::instrument(skip_all, level = "debug")]
109 pub async fn delete_by_episode(&self, episode_id: i32) -> ApiResult<()> {
110 Self::delete_by_episode_with(&self.db, episode_id).await
111 }
112
113 pub async fn count_by_episode_with<C: ConnectionTrait>(
115 db: &C,
116 episode_id: i32,
117 ) -> ApiResult<u64> {
118 Ok(editor_unit::Entity::find()
119 .filter(editor_unit::Column::EpisodeId.eq(episode_id))
120 .count(db)
121 .await?)
122 }
123
124 pub async fn delete_by_episode_with<C: ConnectionTrait>(
126 db: &C,
127 episode_id: i32,
128 ) -> ApiResult<()> {
129 editor_unit::Entity::delete_many()
130 .filter(editor_unit::Column::EpisodeId.eq(episode_id))
131 .exec(db)
132 .await?;
133 Ok(())
134 }
135}