1+ // file_group.rs
2+ //! 文件与分组关联管理模块
3+ //!
4+ //! 提供对文件-分组关系表 (`file_groups`) 的增删查操作支持。
5+
16use super :: models:: { FileGroupCondition , FileGroupDTO } ;
27use crate :: model:: schema:: { file_groups, files} ;
38use diesel:: prelude:: * ;
@@ -6,6 +11,14 @@ use crate::model::models::{File, FileGroupOrderBy, FileGroupQueryOptions, OrderD
611use crate :: utils:: errors:: AppError ;
712use crate :: utils:: errors:: AppError :: CannotUnbindPrimaryGroup ;
813
14+ /// 插入一个新的文件-分组关联记录
15+ ///
16+ /// 参数:
17+ /// - `conn`: 数据库连接对象
18+ /// - `file_group_dto`: 包含待插入数据的 DTO 对象
19+ ///
20+ /// 返回值:
21+ /// 成功时返回影响的行数(通常应为1),失败则返回数据库错误
922pub fn insert_file_group (
1023 conn : & mut AnyConnection ,
1124 file_group_dto : & FileGroupDTO ,
@@ -15,11 +28,21 @@ pub fn insert_file_group(
1528 . execute ( conn)
1629}
1730
31+ /// 根据 DTO 中的信息删除一个文件-分组关联记录
32+ ///
33+ /// 注意:若尝试解除文件与其主分组的关系,则会抛出 `CannotUnbindPrimaryGroup` 错误。
34+ ///
35+ /// 参数:
36+ /// - `conn`: 数据库连接对象
37+ /// - `file_group_dto`: 包含要删除记录信息的 DTO 对象
38+ ///
39+ /// 返回值:
40+ /// 成功时返回影响的行数(通常应为1),失败则返回自定义错误或数据库错误
1841pub fn delete_file_group_by_id (
1942 conn : & mut AnyConnection ,
2043 file_group_dto : & FileGroupDTO ,
2144) -> Result < usize , AppError > {
22- // 判断是否是文件-主组关系 若是则抛异常
45+ // 检查是否试图解绑文件的主分组
2346 let file = files:: table
2447 . select ( File :: as_select ( ) )
2548 . filter ( files:: id. eq ( file_group_dto. file_id ) )
@@ -29,7 +52,7 @@ pub fn delete_file_group_by_id(
2952 return Err ( CannotUnbindPrimaryGroup ) ;
3053 }
3154
32- // 删除关联记录
55+ // 执行实际的删除操作
3356 diesel:: delete (
3457 file_groups:: table
3558 . filter ( file_groups:: group_id. eq ( file_group_dto. group_id ) )
@@ -39,7 +62,13 @@ pub fn delete_file_group_by_id(
3962 . map_err ( AppError :: from) // 将 QueryResult 转换为 AppError
4063}
4164
42- // 将 FileGroupCondition 转换为 diesel 查询条件的辅助函数
65+ /// 构建符合 Diesel 查询语法的条件表达式
66+ ///
67+ /// 参数:
68+ /// - `condition`: 表达查询条件的数据结构
69+ ///
70+ /// 返回值:
71+ /// 符合 Diesel 查询条件类型的动态表达式盒子
4372fn build_file_group_condition ( condition : FileGroupCondition ) -> Box < dyn BoxableExpression < file_groups:: table , <AnyConnection as Connection >:: Backend , SqlType =diesel:: sql_types:: Bool > > {
4473 match condition {
4574 FileGroupCondition :: FileId ( id) => Box :: new ( file_groups:: file_id. eq ( id) ) ,
@@ -63,7 +92,7 @@ fn build_file_group_condition(condition: FileGroupCondition) -> Box<dyn BoxableE
6392 }
6493 }
6594 result. unwrap_or_else ( || Box :: new ( true . into_sql :: < diesel:: sql_types:: Bool > ( ) ) )
66- }
95+ } ,
6796 FileGroupCondition :: Or ( conditions) => {
6897 let mut result: Option < Box < dyn BoxableExpression < file_groups:: table , <AnyConnection as Connection >:: Backend , SqlType =diesel:: sql_types:: Bool > > > = None ;
6998 for cond in conditions {
@@ -74,28 +103,37 @@ fn build_file_group_condition(condition: FileGroupCondition) -> Box<dyn BoxableE
74103 }
75104 }
76105 result. unwrap_or_else ( || Box :: new ( false . into_sql :: < diesel:: sql_types:: Bool > ( ) ) )
77- }
106+ } ,
78107 FileGroupCondition :: Not ( condition) => {
79108 let expr = build_file_group_condition ( * condition) ;
80109 Box :: new ( diesel:: dsl:: not ( expr) )
81110 }
82111 }
83112}
84113
85- // 根据 FileGroupCondition 向量查询文件组关联
114+ /// 根据多个条件查询文件-分组关联记录,并可设置最大返回数量
115+ ///
116+ /// 参数:
117+ /// - `conn`: 数据库连接对象
118+ /// - `conditions`: 查询条件集合,各条件之间采用 AND 连接
119+ /// - `limit`: 最大返回记录数限制(可选)
120+ ///
121+ /// 返回值:
122+ /// 查询成功的记录列表或数据库错误
86123pub fn select_file_groups_by_conditions (
87124 conn : & mut AnyConnection ,
88125 conditions : Vec < FileGroupCondition > ,
89126 limit : Option < i64 > ,
90127) -> Result < Vec < FileGroupDTO > , diesel:: result:: Error > {
91128 let mut query = file_groups:: table. into_boxed :: < <AnyConnection as Connection >:: Backend > ( ) ;
92129
93- // 对每个条件应用 AND 逻辑
130+ // 应用所有条件
94131 for condition in conditions {
95132 let boxed_condition = build_file_group_condition ( condition) ;
96133 query = query. filter ( boxed_condition) ;
97134 }
98135
136+ // 设置返回条目上限
99137 if let Some ( limit) = limit {
100138 query = query. limit ( limit)
101139 }
@@ -105,6 +143,17 @@ pub fn select_file_groups_by_conditions(
105143 . load ( conn)
106144}
107145
146+ /// 根据多个条件和高级选项查询文件-分组关联记录
147+ ///
148+ /// 支持分页、排序等复杂查询需求
149+ ///
150+ /// 参数:
151+ /// - `conn`: 数据库连接对象
152+ /// - `conditions`: 查询条件集合,各条件之间采用 AND 连接
153+ /// - `options`: 查询选项,包括分页和排序配置
154+ ///
155+ /// 返回值:
156+ /// 查询成功的记录列表或数据库错误
108157#[ allow( dead_code) ]
109158pub fn select_file_groups_by_conditions_with_options (
110159 conn : & mut AnyConnection ,
@@ -113,13 +162,13 @@ pub fn select_file_groups_by_conditions_with_options(
113162) -> Result < Vec < FileGroupDTO > , diesel:: result:: Error > {
114163 let mut query = file_groups:: table. into_boxed :: < <AnyConnection as Connection >:: Backend > ( ) ;
115164
116- // 对每个条件应用 AND 逻辑
165+ // 应用所有条件
117166 for condition in conditions {
118167 let boxed_condition = build_file_group_condition ( condition) ;
119168 query = query. filter ( boxed_condition) ;
120169 }
121170
122- // 应用查询选项(排序、限制等)
171+ // 分页设置
123172 if let Some ( limit) = options. limit {
124173 query = query. limit ( limit) ;
125174 }
@@ -128,7 +177,7 @@ pub fn select_file_groups_by_conditions_with_options(
128177 query = query. offset ( offset) ;
129178 }
130179
131- // 应用排序
180+ // 排序设置
132181 for order_by in options. order_by {
133182 query = match order_by {
134183 FileGroupOrderBy :: FileId ( direction) => {
@@ -150,18 +199,60 @@ pub fn select_file_groups_by_conditions_with_options(
150199 . select ( FileGroupDTO :: as_select ( ) )
151200 . load ( conn)
152201}
153-
202+ /// 根据给定条件批量删除文件-分组关联记录
203+ ///
204+ /// 注意:若尝试解除文件与其主分组的关系,则会抛出 `CannotUnbindPrimaryGroup` 错误。
205+ /// 该操作在事务中执行,任何一个删除失败都会导致整个操作回滚。
206+ ///
207+ /// 参数:
208+ /// - `conn`: 数据库连接对象
209+ /// - `conditions`: 删除条件集合,各条件之间采用 AND 连接
210+ ///
211+ /// 返回值:
212+ /// 成功删除的记录数目或数据库错误
154213pub fn delete_file_groups_by_conditions (
155214 conn : & mut AnyConnection ,
156215 conditions : Vec < FileGroupCondition > ,
157- ) -> Result < usize , diesel:: result:: Error > {
158- let mut query = diesel:: delete ( file_groups:: table) . into_boxed :: < <AnyConnection as Connection >:: Backend > ( ) ;
216+ ) -> Result < usize , AppError > {
217+ // 开始事务
218+ conn. transaction :: < usize , AppError , _ > ( |conn| {
219+ // 首先查询将要删除的所有记录
220+ let mut select_query = file_groups:: table. into_boxed :: < <AnyConnection as Connection >:: Backend > ( ) ;
159221
160- // 对每个条件应用 AND 逻辑
161- for condition in conditions {
162- let boxed_condition = build_file_group_condition ( condition) ;
163- query = query. filter ( boxed_condition) ;
164- }
222+ // 应用所有条件到查询
223+ for condition in & conditions {
224+ let boxed_condition = build_file_group_condition ( condition. clone ( ) ) ;
225+ select_query = select_query. filter ( boxed_condition) ;
226+ }
227+
228+ // 获取将要删除的记录
229+ let records_to_delete: Vec < FileGroupDTO > = select_query
230+ . select ( FileGroupDTO :: as_select ( ) )
231+ . load ( conn) ?;
232+
233+ // 检查每条记录是否是文件的主分组关联
234+ for record in & records_to_delete {
235+ let file = files:: table
236+ . select ( File :: as_select ( ) )
237+ . filter ( files:: id. eq ( record. file_id ) )
238+ . first ( conn) ;
239+
240+ // 如果文件存在且该分组是其主分组,则不允许删除
241+ if file. is_ok ( ) && file?. group_id == record. group_id {
242+ return Err ( CannotUnbindPrimaryGroup ) ;
243+ }
244+ }
245+
246+ // 执行实际的删除操作
247+ let mut delete_query = diesel:: delete ( file_groups:: table) . into_boxed :: < <AnyConnection as Connection >:: Backend > ( ) ;
248+
249+ // 应用所有删除条件
250+ for condition in conditions {
251+ let boxed_condition = build_file_group_condition ( condition) ;
252+ delete_query = delete_query. filter ( boxed_condition) ;
253+ }
165254
166- query. execute ( conn)
255+ let deleted_count = delete_query. execute ( conn) ?;
256+ Ok ( deleted_count)
257+ } )
167258}
0 commit comments