Skip to main content

tdm_server_rust/repository/
episode_mapper.rs

1//! 话数查询行映射 (Episode Row Mapper)
2//!
3//! 将 `mangaepisodetb` workflow JOIN 查询结果映射为各 VO 结构体。
4//! 对齐 Java `listEpisode` 的联表查询逻辑。
5
6use crate::entity::{
7    episode::{
8        EpisodeDetailVo, EpisodeListVo, EpisodeSimpleListVo, EpisodeType, NewestEpisodeVo,
9        UploadPageVo,
10    },
11    member::MemberEpisodeVo,
12};
13use chrono::{DateTime, Utc};
14use sqlx::{postgres::PgRow, Row};
15
16/// 话数 workflow JOIN 片段
17pub const EPISODE_WORKFLOW_FROM: &str = r#"
18FROM mangaepisodetb me
19LEFT JOIN mangaepisodedetail med ON me."Id" = med."episodeId"
20LEFT JOIN membertb provider ON me."providerId" = provider."Id"
21LEFT JOIN membertb translator ON me."translatorId" = translator."Id"
22LEFT JOIN membertb proofreader ON me."proofreaderId" = proofreader."Id"
23LEFT JOIN membertb letterer ON me."lettererId" = letterer."Id"
24LEFT JOIN membertb timer ON me."timerId" = timer."Id"
25LEFT JOIN membertb reviewer ON me."reviewerId" = reviewer."Id"
26LEFT JOIN oss providerFile ON providerFile.id = me.provider_file_oss_id
27LEFT JOIN oss translatorFile ON translatorFile.id = me.translator_file_oss_id
28LEFT JOIN oss proofreaderFile ON proofreaderFile.id = me.proofreader_file_oss_id
29LEFT JOIN oss lettererFile ON lettererFile.id = me.letterer_file_oss_id
30LEFT JOIN oss timerFile ON timerFile.id = me.timer_file_oss_id
31"#;
32
33/// 话数 workflow SELECT 列
34pub const EPISODE_WORKFLOW_SELECT: &str = r#"
35me.*,
36med."translatorSetupTime", med."translatorUpdateTime",
37med."proofreaderSetupTime", med."proofreaderUpdateTime",
38med."lettererSetupTime", med."lettererUpdateTime",
39med."timerSetupTime", med."timerUpdateTime",
40med."reviewerSetupTime", med."reviewerUpdateTime",
41provider.username AS providerName,
42translator.username AS translatorName,
43proofreader.username AS proofreaderName,
44letterer.username AS lettererName,
45timer.username AS timerName,
46reviewer.username AS reviewerName,
47providerFile.filename AS providerFilename,
48translatorFile.filename AS translatorFilename,
49proofreaderFile.filename AS proofreaderFilename,
50lettererFile.filename AS lettererFilename,
51timerFile.filename AS timerFilename,
52(SELECT COUNT(1)::BIGINT FROM editor_page epg WHERE epg.episode_id = me."Id") AS "editorPageCount"
53"#;
54
55fn try_dt(row: &PgRow, col: &str) -> Option<DateTime<Utc>> {
56    crate::utils::legacy_time::try_dt(row, col)
57}
58
59fn try_i32(row: &PgRow, col: &str) -> Option<i32> {
60    row.try_get(col).ok()
61}
62
63fn try_str(row: &PgRow, col: &str) -> Option<String> {
64    row.try_get(col).ok().or_else(|| {
65        let lower = col.to_ascii_lowercase();
66        row.try_get(lower.as_str()).ok()
67    })
68}
69
70/// 映射为话数列表 VO
71pub fn row_to_episode_list(row: &PgRow) -> EpisodeListVo {
72    EpisodeListVo {
73        id: row.try_get("Id").unwrap_or(0),
74        manga_id: row.try_get("mangaId").unwrap_or(0),
75        manga_episode: try_str(row, "mangaEpisode"),
76        manga_episode_name: try_str(row, "mangaEpisodeName"),
77        episode_type: if try_str(row, "episodeType").as_deref() == Some(EpisodeType::Extra.as_str())
78        {
79            EpisodeType::Extra
80        } else {
81            EpisodeType::Main
82        },
83        provider_id: try_i32(row, "providerId"),
84        translator_id: try_i32(row, "translatorId"),
85        proofreader_id: try_i32(row, "proofreaderId"),
86        letterer_id: try_i32(row, "lettererId"),
87        timer_id: try_i32(row, "timerId"),
88        reviewer_id: try_i32(row, "reviewerId"),
89        setup_time: try_dt(row, "setupTime"),
90        update_time: try_dt(row, "updateTime"),
91        translator_file: try_str(row, "translatorFile"),
92        proofreader_file: try_str(row, "proofreaderFile"),
93        timer_file: try_str(row, "timerFile"),
94        publish_link: try_str(row, "publishLink"),
95        provider_file_oss_id: try_i32(row, "provider_file_oss_id"),
96        editor_page_count: row.try_get("editorPageCount").unwrap_or(0),
97        translator_file_oss_id: try_i32(row, "translator_file_oss_id"),
98        proofreader_file_oss_id: try_i32(row, "proofreader_file_oss_id"),
99        letterer_file_oss_id: try_i32(row, "letterer_file_oss_id"),
100        timer_file_oss_id: try_i32(row, "timer_file_oss_id"),
101        translator_setup_time: try_dt(row, "translatorSetupTime"),
102        translator_update_time: try_dt(row, "translatorUpdateTime"),
103        proofreader_setup_time: try_dt(row, "proofreaderSetupTime"),
104        proofreader_update_time: try_dt(row, "proofreaderUpdateTime"),
105        letterer_setup_time: try_dt(row, "lettererSetupTime"),
106        letterer_update_time: try_dt(row, "lettererUpdateTime"),
107        timer_setup_time: try_dt(row, "timerSetupTime"),
108        timer_update_time: try_dt(row, "timerUpdateTime"),
109        reviewer_setup_time: try_dt(row, "reviewerSetupTime"),
110        reviewer_update_time: try_dt(row, "reviewerUpdateTime"),
111        provider_name: try_str(row, "providerName"),
112        translator_name: try_str(row, "translatorName"),
113        proofreader_name: try_str(row, "proofreaderName"),
114        letterer_name: try_str(row, "lettererName"),
115        timer_name: try_str(row, "timerName"),
116        reviewer_name: try_str(row, "reviewerName"),
117        provider_filename: try_str(row, "providerFilename"),
118        translator_filename: try_str(row, "translatorFilename"),
119        proofreader_filename: try_str(row, "proofreaderFilename"),
120        letterer_filename: try_str(row, "lettererFilename"),
121        timer_filename: try_str(row, "timerFilename"),
122        translator_co_takers: Vec::new(),
123        proofreader_co_takers: Vec::new(),
124    }
125}
126
127/// 映射为话数简单列表 VO
128pub fn row_to_episode_simple(row: &PgRow) -> EpisodeSimpleListVo {
129    let full = row_to_episode_list(row);
130    EpisodeSimpleListVo {
131        id: full.id,
132        manga_episode: full.manga_episode,
133        manga_episode_name: full.manga_episode_name,
134        episode_type: full.episode_type,
135        translator_file: full.translator_file,
136        proofreader_file: full.proofreader_file,
137        timer_file: full.timer_file,
138        provider_file_oss_id: full.provider_file_oss_id,
139        editor_page_count: full.editor_page_count,
140        translator_file_oss_id: full.translator_file_oss_id,
141        proofreader_file_oss_id: full.proofreader_file_oss_id,
142        letterer_file_oss_id: full.letterer_file_oss_id,
143        timer_file_oss_id: full.timer_file_oss_id,
144        publish_link: full.publish_link,
145    }
146}
147
148/// 映射为话数详情 VO
149pub fn row_to_episode_detail(row: &PgRow) -> EpisodeDetailVo {
150    let full = row_to_episode_list(row);
151    EpisodeDetailVo {
152        id: full.id,
153        manga_id: full.manga_id,
154        manga_episode: full.manga_episode,
155        manga_episode_name: full.manga_episode_name,
156        episode_type: full.episode_type,
157        provider_id: full.provider_id,
158        translator_id: full.translator_id,
159        proofreader_id: full.proofreader_id,
160        letterer_id: full.letterer_id,
161        timer_id: full.timer_id,
162        reviewer_id: full.reviewer_id,
163        setup_time: full.setup_time,
164        update_time: full.update_time,
165        publish_link: full.publish_link,
166    }
167}
168
169/// 映射为最新话 VO
170pub fn row_to_newest(row: &PgRow) -> NewestEpisodeVo {
171    NewestEpisodeVo {
172        manga_episode: try_str(row, "mangaEpisode"),
173        translator_id: try_i32(row, "translatorId"),
174        proofreader_id: try_i32(row, "proofreaderId"),
175        letterer_id: try_i32(row, "lettererId"),
176        reviewer_id: try_i32(row, "reviewerId"),
177    }
178}
179
180/// 映射为组员话数 VO
181pub fn row_to_member_episode(row: &PgRow) -> MemberEpisodeVo {
182    let full = row_to_episode_list(row);
183    MemberEpisodeVo {
184        id: full.id,
185        manga_id: full.manga_id,
186        manga_name: try_str(row, "mangaName"),
187        manga_episode: full.manga_episode,
188        manga_episode_name: full.manga_episode_name,
189        setup_time: full.setup_time,
190        update_time: full.update_time,
191        provider_id: full.provider_id,
192        provider_name: full.provider_name,
193        provider_setup_time: try_dt(row, "providerSetupTime"),
194        provider_update_time: try_dt(row, "providerUpdateTime"),
195        translator_id: full.translator_id,
196        translator_name: full.translator_name,
197        translator_setup_time: full.translator_setup_time,
198        translator_update_time: full.translator_update_time,
199        proofreader_id: full.proofreader_id,
200        proofreader_name: full.proofreader_name,
201        proofreader_setup_time: full.proofreader_setup_time,
202        proofreader_update_time: full.proofreader_update_time,
203        letterer_id: full.letterer_id,
204        letterer_name: full.letterer_name,
205        letterer_setup_time: full.letterer_setup_time,
206        letterer_update_time: full.letterer_update_time,
207        timer_id: full.timer_id,
208        timer_name: full.timer_name,
209        timer_setup_time: full.timer_setup_time,
210        timer_update_time: full.timer_update_time,
211        reviewer_id: full.reviewer_id,
212        reviewer_name: full.reviewer_name,
213        reviewer_setup_time: full.reviewer_setup_time,
214        reviewer_update_time: full.reviewer_update_time,
215        provider_file_oss_id: full.provider_file_oss_id,
216        provider_filename: full.provider_filename,
217        translator_file_oss_id: full.translator_file_oss_id,
218        translator_filename: full.translator_filename,
219        proofreader_file_oss_id: full.proofreader_file_oss_id,
220        proofreader_filename: full.proofreader_filename,
221        letterer_file_oss_id: full.letterer_file_oss_id,
222        letterer_filename: full.letterer_filename,
223        timer_file_oss_id: full.timer_file_oss_id,
224        timer_filename: full.timer_filename,
225        translator_file: full.translator_file,
226        proofreader_file: full.proofreader_file,
227        timer_file: full.timer_file,
228        publish_link: full.publish_link,
229        workbench_time: None,
230    }
231}
232
233/// 映射为上传页 VO(仅读取藏宝处查询列,避免 med/workflow 无效 lookup)
234pub fn row_to_upload_page(row: &PgRow) -> UploadPageVo {
235    UploadPageVo {
236        id: row.try_get("Id").unwrap_or(0),
237        manga_id: row.try_get("mangaId").unwrap_or(0),
238        manga_name: try_str(row, "mangaName"),
239        manga_episode: try_str(row, "mangaEpisode"),
240        update_time: try_dt(row, "updateTime"),
241        translator_file: try_str(row, "translatorFile"),
242        proofreader_file: try_str(row, "proofreaderFile"),
243        timer_file: try_str(row, "timerFile"),
244        provider_id: try_i32(row, "providerId"),
245        translator_id: try_i32(row, "translatorId"),
246        proofreader_id: try_i32(row, "proofreaderId"),
247        letterer_id: try_i32(row, "lettererId"),
248        timer_id: try_i32(row, "timerId"),
249        reviewer_id: try_i32(row, "reviewerId"),
250        provider_name: None,
251        translator_name: try_str(row, "translatorName"),
252        proofreader_name: try_str(row, "proofreaderName"),
253        letterer_name: try_str(row, "lettererName"),
254        timer_name: try_str(row, "timerName"),
255        reviewer_name: try_str(row, "reviewerName"),
256        provider_file_oss_id: try_i32(row, "provider_file_oss_id"),
257        translator_file_oss_id: try_i32(row, "translator_file_oss_id"),
258        proofreader_file_oss_id: try_i32(row, "proofreader_file_oss_id"),
259        letterer_file_oss_id: try_i32(row, "letterer_file_oss_id"),
260        timer_file_oss_id: try_i32(row, "timer_file_oss_id"),
261        provider_filename: try_str(row, "providerFilename"),
262        translator_filename: try_str(row, "translatorFilename"),
263        proofreader_filename: try_str(row, "proofreaderFilename"),
264        letterer_filename: try_str(row, "lettererFilename"),
265        timer_filename: try_str(row, "timerFilename"),
266        email: try_str(row, "email"),
267        email_now: try_str(row, "emailNow"),
268    }
269}