1use crate::cycle_detection::{CycleDetector, CyclePolicy};
27use crate::pool::Connection;
28use crate::relation_trait::RelationDef;
29use crate::value::Value;
30use crate::DbError;
31
32use std::collections::HashMap;
33
34pub type EagerResult = (HashMap<String, Value>, Vec<HashMap<String, Value>>);
36
37#[derive(Debug, Clone)]
55pub enum NestedEagerResult {
56 Leaf(HashMap<String, Value>),
58 Node {
60 row: HashMap<String, Value>,
62 children: Vec<NestedEagerResult>,
64 },
65}
66
67impl NestedEagerResult {
68 pub fn row(&self) -> &HashMap<String, Value> {
70 match self {
71 NestedEagerResult::Leaf(row) => row,
72 NestedEagerResult::Node { row, .. } => row,
73 }
74 }
75
76 pub fn children(&self) -> &[NestedEagerResult] {
78 match self {
79 NestedEagerResult::Leaf(_) => &[],
80 NestedEagerResult::Node { children, .. } => children,
81 }
82 }
83
84 pub fn is_leaf(&self) -> bool {
86 matches!(self, NestedEagerResult::Leaf(_))
87 }
88}
89
90struct ChildLoadConfig {
92 relation: RelationDef,
93 children: Vec<ChildLoadConfig>,
95}
96
97impl ChildLoadConfig {
98 fn push_to_deepest(&mut self, child: ChildLoadConfig) {
100 if self.children.is_empty() {
101 self.children.push(child);
102 } else {
103 self.children.last_mut().unwrap().push_to_deepest(child);
104 }
105 }
106
107 fn chain_depth(&self) -> usize {
109 if self.children.is_empty() {
110 1
111 } else {
112 1 + self.children[0].chain_depth()
113 }
114 }
115
116 fn chain_names(&self) -> Vec<&str> {
118 let mut names = vec![std::borrow::Borrow::<str>::borrow(&self.relation.name)];
119 if !self.children.is_empty() {
120 names.extend(self.children[0].chain_names());
121 }
122 names
123 }
124}
125
126pub struct EagerLoader {
130 relation: RelationDef,
131 children: Vec<ChildLoadConfig>,
132 cycle_policy: CyclePolicy,
134}
135
136impl EagerLoader {
137 pub fn new(relation: RelationDef) -> Self {
139 Self {
140 relation,
141 children: Vec::new(),
142 cycle_policy: CyclePolicy::default(),
143 }
144 }
145
146 pub fn with(mut self, relation: RelationDef) -> Self {
157 let new_child = ChildLoadConfig {
158 relation,
159 children: Vec::new(),
160 };
161 if self.children.is_empty() {
162 self.children.push(new_child);
163 } else {
164 self.children.last_mut().unwrap().push_to_deepest(new_child);
165 }
166 self
167 }
168
169 pub fn with_cycle_policy(mut self, policy: CyclePolicy) -> Self {
179 self.cycle_policy = policy;
180 self
181 }
182
183 pub fn smart(self) -> crate::smart_eager_loader::SmartEagerLoader {
203 let mut smart = crate::smart_eager_loader::SmartEagerLoader::new(self.relation)
204 .with_cycle_policy(self.cycle_policy);
205 for child in &self.children {
206 let relations = collect_child_relations(child);
207 for rel in relations {
208 smart = smart.with(rel);
209 }
210 }
211 smart
212 }
213
214 pub fn children_count(&self) -> usize {
216 if self.children.is_empty() {
217 0
218 } else {
219 self.children[0].chain_depth()
220 }
221 }
222
223 pub fn child_names(&self) -> Vec<&str> {
225 if self.children.is_empty() {
226 Vec::new()
227 } else {
228 self.children[0].chain_names()
229 }
230 }
231
232 pub async fn load_many(
239 &self,
240 conn: &mut dyn Connection,
241 main_sql: &str,
242 ) -> Result<Vec<EagerResult>, DbError> {
243 let main_rows = conn.query(main_sql).await?;
244
245 if main_rows.is_empty() {
246 return Ok(Vec::new());
247 }
248
249 let pk_values = self.extract_primary_keys(&main_rows);
250 if pk_values.is_empty() {
251 return Ok(main_rows.into_iter().map(|r| (r, Vec::new())).collect());
252 }
253
254 let related_rows = self.batch_query_related(conn, &pk_values).await?;
255 let grouped = self.group_by_foreign_key(related_rows, self.relation.to_key);
256
257 if !self.children.is_empty() {
259 let all_related: Vec<&HashMap<String, Value>> = grouped.values().flatten().collect();
260 let all_related_owned: Vec<HashMap<String, Value>> =
261 all_related.into_iter().cloned().collect();
262 let _child_groups = self.load_children(conn, &all_related_owned).await?;
263 }
265
266 let results = main_rows
267 .into_iter()
268 .map(|row| {
269 let pk = row
270 .get(self.relation.from_key)
271 .cloned()
272 .unwrap_or(Value::Null);
273 let pk_key = value_to_key(&pk);
274 let related = grouped.get(&pk_key).cloned().unwrap_or_default();
275 (row, related)
276 })
277 .collect();
278
279 Ok(results)
280 }
281
282 async fn load_children(
286 &self,
287 conn: &mut dyn Connection,
288 parent_rows: &[HashMap<String, Value>],
289 ) -> Result<HashMap<String, Vec<HashMap<String, Value>>>, DbError> {
290 if self.children.is_empty() || parent_rows.is_empty() {
291 return Ok(HashMap::new());
292 }
293
294 let child_relation = &self.children[0].relation;
295 let pk_values: Vec<Value> = parent_rows
296 .iter()
297 .filter_map(|row| row.get(child_relation.from_key).cloned())
298 .collect();
299
300 if pk_values.is_empty() {
301 return Ok(HashMap::new());
302 }
303
304 let mut all_child_rows = Vec::new();
305 for chunk in pk_values.chunks(1000) {
306 let placeholders: Vec<String> = (0..chunk.len()).map(|_| "?".to_string()).collect();
307 let sql = format!(
308 "SELECT * FROM {} WHERE {} IN ({})",
309 child_relation.to_entity,
310 child_relation.to_key,
311 placeholders.join(", ")
312 );
313 let rows = conn.query_with_params(&sql, chunk).await?;
314 all_child_rows.extend(rows);
315 }
316
317 Ok(self.group_by_foreign_key(all_child_rows, child_relation.to_key))
318 }
319
320 pub async fn load_nested(
352 &self,
353 conn: &mut dyn Connection,
354 main_sql: &str,
355 ) -> Result<Vec<NestedEagerResult>, DbError> {
356 let mut detector = CycleDetector::new(self.cycle_policy);
357 let main_rows = conn.query(main_sql).await?;
358
359 if main_rows.is_empty() {
360 return Ok(Vec::new());
361 }
362
363 const MAX_RESULT_SIZE: usize = 1_000_000;
364 if main_rows.len() > MAX_RESULT_SIZE {
365 return Err(DbError::InvalidInput(format!(
366 "结果集超内存限制({} 行),建议改用 Stream API 处理大结果集",
367 main_rows.len()
368 )));
369 }
370
371 if self.children.is_empty() {
372 return Ok(main_rows.into_iter().map(NestedEagerResult::Leaf).collect());
373 }
374
375 let first_child = &self.children[0];
376 self.load_level_nested(
377 conn,
378 main_rows,
379 &first_child.relation,
380 &first_child.children,
381 &mut detector,
382 )
383 .await
384 }
385
386 async fn load_level_nested(
388 &self,
389 conn: &mut dyn Connection,
390 parent_rows: Vec<HashMap<String, Value>>,
391 relation: &RelationDef,
392 child_configs: &[ChildLoadConfig],
393 detector: &mut CycleDetector,
394 ) -> Result<Vec<NestedEagerResult>, DbError> {
395 let can_continue = detector.check(relation.from_entity, relation.name)?;
396 if !can_continue {
397 return Ok(parent_rows
398 .into_iter()
399 .map(NestedEagerResult::Leaf)
400 .collect());
401 }
402
403 detector.enter(relation.from_entity, relation.name);
404
405 let pk_values: Vec<Value> = parent_rows
406 .iter()
407 .filter_map(|row| row.get(relation.from_key).cloned())
408 .collect();
409
410 if pk_values.is_empty() {
411 detector.leave();
412 return Ok(parent_rows
413 .into_iter()
414 .map(|row| NestedEagerResult::Node {
415 row,
416 children: Vec::new(),
417 })
418 .collect());
419 }
420
421 let related_rows = batch_query_with_relation(conn, relation, &pk_values).await?;
422 let grouped = group_rows_by_foreign_key(related_rows, relation.to_key);
423
424 let mut results = Vec::with_capacity(parent_rows.len());
425 for parent_row in parent_rows {
426 let pk = parent_row
427 .get(relation.from_key)
428 .cloned()
429 .unwrap_or(Value::Null);
430 let pk_key = value_to_key(&pk);
431 let child_rows = grouped.get(&pk_key).cloned().unwrap_or_default();
432
433 let children = if child_rows.is_empty() {
434 Vec::new()
435 } else if child_configs.is_empty() {
436 child_rows
437 .into_iter()
438 .map(NestedEagerResult::Leaf)
439 .collect()
440 } else {
441 let next_config = &child_configs[0];
442 Box::pin(self.load_level_nested(
443 conn,
444 child_rows,
445 &next_config.relation,
446 &next_config.children,
447 detector,
448 ))
449 .await?
450 };
451
452 results.push(NestedEagerResult::Node {
453 row: parent_row,
454 children,
455 });
456 }
457
458 detector.leave();
459 Ok(results)
460 }
461
462 fn extract_primary_keys(&self, rows: &[HashMap<String, Value>]) -> Vec<Value> {
464 rows.iter()
465 .filter_map(|row| row.get(self.relation.from_key).cloned())
466 .collect()
467 }
468
469 async fn batch_query_related(
471 &self,
472 conn: &mut dyn Connection,
473 pk_values: &[Value],
474 ) -> Result<Vec<HashMap<String, Value>>, DbError> {
475 let batch_size = 1000;
476 let mut all_rows = Vec::new();
477
478 for chunk in pk_values.chunks(batch_size) {
479 let sql = self.build_related_sql(chunk.len());
480 let rows = conn.query_with_params(&sql, chunk).await?;
481 all_rows.extend(rows);
482 }
483
484 Ok(all_rows)
485 }
486
487 fn build_related_sql(&self, param_count: usize) -> String {
489 let placeholders: Vec<String> = (0..param_count).map(|_| "?".to_string()).collect();
490 format!(
491 "SELECT * FROM {} WHERE {} IN ({})",
492 self.relation.to_entity,
493 self.relation.to_key,
494 placeholders.join(", ")
495 )
496 }
497
498 fn group_by_foreign_key(
500 &self,
501 rows: Vec<HashMap<String, Value>>,
502 fk_key: &str,
503 ) -> HashMap<String, Vec<HashMap<String, Value>>> {
504 let mut grouped: HashMap<String, Vec<HashMap<String, Value>>> = HashMap::new();
505 for row in rows {
506 let fk = row.get(fk_key).cloned().unwrap_or(Value::Null);
507 let key = value_to_key(&fk);
508 grouped.entry(key).or_default().push(row);
509 }
510 grouped
511 }
512}
513
514fn collect_child_relations(config: &ChildLoadConfig) -> Vec<RelationDef> {
516 let mut relations = vec![config.relation.clone()];
517 for child in &config.children {
518 relations.extend(collect_child_relations(child));
519 }
520 relations
521}
522
523fn value_to_key(value: &Value) -> String {
525 match value {
526 Value::Null => "null".to_string(),
527 Value::Bool(b) => format!("bool:{}", b),
528 Value::I8(v) => format!("i8:{}", v),
529 Value::I16(v) => format!("i16:{}", v),
530 Value::I32(v) => format!("i32:{}", v),
531 Value::I64(v) => format!("i64:{}", v),
532 Value::U8(v) => format!("u8:{}", v),
533 Value::U16(v) => format!("u16:{}", v),
534 Value::U32(v) => format!("u32:{}", v),
535 Value::U64(v) => format!("u64:{}", v),
536 Value::F32(v) => format!("f32:{}", v),
537 Value::F64(v) => format!("f64:{}", v),
538 Value::String(s) => format!("str:{}", s),
539 _ => format!("other:{:?}", value),
540 }
541}
542
543async fn batch_query_with_relation(
545 conn: &mut dyn Connection,
546 relation: &RelationDef,
547 pk_values: &[Value],
548) -> Result<Vec<HashMap<String, Value>>, DbError> {
549 let batch_size = 1000;
550 let mut all_rows = Vec::new();
551
552 for chunk in pk_values.chunks(batch_size) {
553 let placeholders: Vec<String> = (0..chunk.len()).map(|_| "?".to_string()).collect();
554 let sql = format!(
555 "SELECT * FROM {} WHERE {} IN ({})",
556 relation.to_entity,
557 relation.to_key,
558 placeholders.join(", ")
559 );
560 let rows = conn.query_with_params(&sql, chunk).await?;
561 all_rows.extend(rows);
562 }
563
564 Ok(all_rows)
565}
566
567fn group_rows_by_foreign_key(
569 rows: Vec<HashMap<String, Value>>,
570 fk_key: &str,
571) -> HashMap<String, Vec<HashMap<String, Value>>> {
572 let mut grouped: HashMap<String, Vec<HashMap<String, Value>>> = HashMap::new();
573 for row in rows {
574 let fk = row.get(fk_key).cloned().unwrap_or(Value::Null);
575 let key = value_to_key(&fk);
576 grouped.entry(key).or_default().push(row);
577 }
578 grouped
579}
580
581pub async fn eager_load_all(
603 conn: &mut dyn Connection,
604 main_sql: &str,
605 relation: &RelationDef,
606) -> Result<Vec<EagerResult>, DbError> {
607 let loader = EagerLoader::new(relation.clone());
608 loader.load_many(conn, main_sql).await
609}
610
611pub async fn eager_load_one(
615 conn: &mut dyn Connection,
616 main_sql: &str,
617 relation: &RelationDef,
618) -> Result<Vec<(HashMap<String, Value>, Option<HashMap<String, Value>>)>, DbError> {
619 let main_rows = conn.query(main_sql).await?;
620
621 if main_rows.is_empty() {
622 return Ok(Vec::new());
623 }
624
625 let fk_values: Vec<Value> = main_rows
626 .iter()
627 .filter_map(|row| row.get(relation.to_key).cloned())
628 .collect();
629
630 if fk_values.is_empty() {
631 return Ok(main_rows.into_iter().map(|r| (r, None)).collect());
632 }
633
634 let placeholder: Vec<String> = (0..fk_values.len()).map(|_| "?".to_string()).collect();
635 let related_sql = format!(
636 "SELECT * FROM {} WHERE {} IN ({})",
637 relation.to_entity,
638 relation.from_key,
639 placeholder.join(", ")
640 );
641
642 let related_rows = conn.query_with_params(&related_sql, &fk_values).await?;
643
644 let mut related_map: HashMap<String, HashMap<String, Value>> = HashMap::new();
645 for row in related_rows {
646 let pk = row.get(relation.from_key).cloned().unwrap_or(Value::Null);
647 related_map.insert(value_to_key(&pk), row);
648 }
649
650 let results = main_rows
651 .into_iter()
652 .map(|row| {
653 let fk = row.get(relation.to_key).cloned().unwrap_or(Value::Null);
654 let related = related_map.get(&value_to_key(&fk)).cloned();
655 (row, related)
656 })
657 .collect();
658
659 Ok(results)
660}
661
662#[cfg(test)]
663mod tests {
664 use super::*;
665 use crate::relation_trait::RelationKind;
666
667 #[test]
668 fn test_eager_loader_new() {
669 let relation = RelationDef::new(
670 "orders",
671 "users",
672 "orders",
673 "id",
674 "user_id",
675 RelationKind::HasMany,
676 );
677 let loader = EagerLoader::new(relation);
678 assert_eq!(loader.relation.name, "orders");
679 assert!(loader.children.is_empty());
680 }
681
682 #[test]
683 fn test_eager_loader_with_children() {
684 let relation = RelationDef::new(
685 "orders",
686 "users",
687 "orders",
688 "id",
689 "user_id",
690 RelationKind::HasMany,
691 );
692 let child_relation = RelationDef::new(
693 "items",
694 "orders",
695 "order_items",
696 "id",
697 "order_id",
698 RelationKind::HasMany,
699 );
700 let loader = EagerLoader::new(relation).with(child_relation);
701 assert_eq!(loader.children.len(), 1);
702 }
703
704 #[test]
705 fn test_build_related_sql() {
706 let relation = RelationDef::new(
707 "orders",
708 "users",
709 "orders",
710 "id",
711 "user_id",
712 RelationKind::HasMany,
713 );
714 let loader = EagerLoader::new(relation);
715 let sql = loader.build_related_sql(3);
716 assert!(sql.contains("SELECT * FROM orders"));
717 assert!(sql.contains("user_id IN (?, ?, ?)"));
718 }
719
720 #[test]
721 fn test_extract_primary_keys() {
722 let relation = RelationDef::new(
723 "orders",
724 "users",
725 "orders",
726 "id",
727 "user_id",
728 RelationKind::HasMany,
729 );
730 let loader = EagerLoader::new(relation);
731
732 let mut row1 = HashMap::new();
733 row1.insert("id".to_string(), Value::I64(1));
734 let mut row2 = HashMap::new();
735 row2.insert("id".to_string(), Value::I64(2));
736
737 let pks = loader.extract_primary_keys(&[row1, row2]);
738 assert_eq!(pks.len(), 2);
739 }
740
741 #[test]
742 fn test_group_by_foreign_key() {
743 let relation = RelationDef::new(
744 "orders",
745 "users",
746 "orders",
747 "id",
748 "user_id",
749 RelationKind::HasMany,
750 );
751 let loader = EagerLoader::new(relation);
752
753 let mut row1 = HashMap::new();
754 row1.insert("user_id".to_string(), Value::I64(1));
755 row1.insert("id".to_string(), Value::I64(101));
756 let mut row2 = HashMap::new();
757 row2.insert("user_id".to_string(), Value::I64(1));
758 row2.insert("id".to_string(), Value::I64(102));
759 let mut row3 = HashMap::new();
760 row3.insert("user_id".to_string(), Value::I64(2));
761 row3.insert("id".to_string(), Value::I64(103));
762
763 let grouped = loader.group_by_foreign_key(vec![row1, row2, row3], "user_id");
764 assert_eq!(grouped.len(), 2);
765 assert_eq!(grouped.get("i64:1").unwrap().len(), 2);
766 assert_eq!(grouped.get("i64:2").unwrap().len(), 1);
767 }
768
769 #[test]
770 fn test_nested_eager_result_leaf() {
771 let mut row = HashMap::new();
772 row.insert("id".to_string(), Value::I64(1));
773 let leaf = NestedEagerResult::Leaf(row.clone());
774 assert!(leaf.is_leaf());
775 assert_eq!(leaf.row().get("id"), Some(&Value::I64(1)));
776 assert!(leaf.children().is_empty());
777 }
778
779 #[test]
780 fn test_nested_eager_result_node() {
781 let mut row = HashMap::new();
782 row.insert("id".to_string(), Value::I64(1));
783 let child = NestedEagerResult::Leaf(HashMap::new());
784 let node = NestedEagerResult::Node {
785 row: row.clone(),
786 children: vec![child],
787 };
788 assert!(!node.is_leaf());
789 assert_eq!(node.row().get("id"), Some(&Value::I64(1)));
790 assert_eq!(node.children().len(), 1);
791 assert!(node.children()[0].is_leaf());
792 }
793
794 #[test]
795 fn test_eager_loader_4_level_chain() {
796 let rel1 = RelationDef::new(
797 "orders",
798 "users",
799 "orders",
800 "id",
801 "user_id",
802 RelationKind::HasMany,
803 );
804 let rel2 = RelationDef::new(
805 "items",
806 "orders",
807 "order_items",
808 "id",
809 "order_id",
810 RelationKind::HasMany,
811 );
812 let rel3 = RelationDef::new(
813 "product",
814 "order_items",
815 "products",
816 "id",
817 "product_id",
818 RelationKind::BelongsTo,
819 );
820 let loader = EagerLoader::new(rel1).with(rel2).with(rel3);
821 assert_eq!(loader.children_count(), 2);
822 assert_eq!(loader.child_names(), vec!["items", "product"]);
823 }
824
825 #[test]
826 fn test_eager_loader_with_cycle_policy() {
827 let rel = RelationDef::new(
828 "orders",
829 "users",
830 "orders",
831 "id",
832 "user_id",
833 RelationKind::HasMany,
834 );
835 let loader = EagerLoader::new(rel).with_cycle_policy(CyclePolicy::Error);
836 assert_eq!(loader.cycle_policy, CyclePolicy::Error);
837 }
838
839 #[test]
840 fn test_eager_loader_default_cycle_policy() {
841 let rel = RelationDef::new(
842 "orders",
843 "users",
844 "orders",
845 "id",
846 "user_id",
847 RelationKind::HasMany,
848 );
849 let loader = EagerLoader::new(rel);
850 assert_eq!(loader.cycle_policy, CyclePolicy::Truncate);
851 }
852
853 #[test]
854 fn test_eager_loader_chain_depth_limit() {
855 let rel1 = RelationDef::new("a", "t0", "t1", "id", "t0_id", RelationKind::HasMany);
856 let rel2 = RelationDef::new("b", "t1", "t2", "id", "t1_id", RelationKind::HasMany);
857 let rel3 = RelationDef::new("c", "t2", "t3", "id", "t2_id", RelationKind::HasMany);
858 let rel4 = RelationDef::new("d", "t3", "t4", "id", "t3_id", RelationKind::HasMany);
859 let loader = EagerLoader::new(rel1).with(rel2).with(rel3).with(rel4);
860 assert_eq!(loader.children_count(), 3);
861 assert_eq!(loader.child_names(), vec!["b", "c", "d"]);
862 }
863
864 #[test]
865 fn test_eager_loader_backward_compat_2_level() {
866 let rel1 = RelationDef::new(
867 "orders",
868 "users",
869 "orders",
870 "id",
871 "user_id",
872 RelationKind::HasMany,
873 );
874 let rel2 = RelationDef::new(
875 "items",
876 "orders",
877 "order_items",
878 "id",
879 "order_id",
880 RelationKind::HasMany,
881 );
882 let loader = EagerLoader::new(rel1).with(rel2);
883 assert_eq!(loader.children.len(), 1);
884 assert_eq!(loader.children_count(), 1);
885 assert_eq!(loader.child_names(), vec!["items"]);
886 }
887}