rust_ef/
dependency_graph.rs1use std::any::TypeId;
11use std::collections::{HashMap, VecDeque};
12use crate::metadata::EntityTypeMeta;
13
14pub struct DependencyGraph {
15 edges: HashMap<TypeId, Vec<TypeId>>,
17 nodes: Vec<TypeId>,
18}
19
20impl DependencyGraph {
21 pub fn build(metas: &HashMap<TypeId, EntityTypeMeta>) -> Self {
25 let mut edges: HashMap<TypeId, Vec<TypeId>> = HashMap::new();
26 let mut nodes: Vec<TypeId> = Vec::new();
27 for (type_id, meta) in metas {
28 nodes.push(*type_id);
29 for nav in &meta.navigations {
30 if matches!(
31 nav.kind,
32 crate::metadata::NavigationKind::HasMany
33 | crate::metadata::NavigationKind::ManyToMany
34 ) {
35 edges
36 .entry(nav.related_type_id)
37 .or_default()
38 .push(*type_id);
39 }
40 }
41 }
42 Self { edges, nodes }
43 }
44
45 pub fn topological_sort(&self) -> Vec<TypeId> {
50 let mut in_degree: HashMap<TypeId, usize> = HashMap::new();
51 for node in &self.nodes {
52 in_degree.entry(*node).or_insert(0);
53 }
54 for (child, parents) in &self.edges {
55 let count = parents.iter().filter(|p| **p != *child).count();
56 *in_degree.entry(*child).or_insert(0) += count;
57 }
58
59 let mut queue: VecDeque<TypeId> = in_degree
60 .iter()
61 .filter(|(_, °)| deg == 0)
62 .map(|(&k, _)| k)
63 .collect();
64 let mut result: Vec<TypeId> = Vec::new();
65 while let Some(node) = queue.pop_front() {
66 result.push(node);
67 for (child, parents) in &self.edges {
68 if parents.iter().any(|p| *p == node && *p != *child) {
69 let deg = in_degree.entry(*child).or_insert(0);
70 if *deg > 0 {
71 *deg -= 1;
72 }
73 if *deg == 0 && !result.contains(child) && !queue.contains(child) {
74 queue.push_back(*child);
75 }
76 }
77 }
78 }
79 for node in &self.nodes {
80 if !result.contains(node) {
81 result.push(*node);
82 }
83 }
84 result
85 }
86
87 pub fn deletion_order(&self) -> Vec<TypeId> {
89 let mut order = self.topological_sort();
90 order.reverse();
91 order
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn empty_graph_returns_empty() {
101 let metas: HashMap<TypeId, EntityTypeMeta> = HashMap::new();
102 let graph = DependencyGraph::build(&metas);
103 assert!(graph.topological_sort().is_empty());
104 }
105
106 #[test]
107 fn deletion_order_is_reverse_of_insert() {
108 let metas: HashMap<TypeId, EntityTypeMeta> = HashMap::new();
109 let graph = DependencyGraph::build(&metas);
110 let insert = graph.topological_sort();
111 let delete = graph.deletion_order();
112 assert_eq!(delete, insert.into_iter().rev().collect::<Vec<_>>());
113 }
114}