rust_ef/
dependency_graph.rs1use crate::metadata::EntityTypeMeta;
11use std::any::TypeId;
12use std::collections::{HashMap, VecDeque};
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.entry(nav.related_type_id).or_default().push(*type_id);
36 }
37 }
38 }
39 Self { edges, nodes }
40 }
41
42 pub fn topological_sort(&self) -> Vec<TypeId> {
47 let mut in_degree: HashMap<TypeId, usize> = HashMap::new();
48 for node in &self.nodes {
49 in_degree.entry(*node).or_insert(0);
50 }
51 for (child, parents) in &self.edges {
52 let count = parents.iter().filter(|p| **p != *child).count();
53 *in_degree.entry(*child).or_insert(0) += count;
54 }
55
56 let mut queue: VecDeque<TypeId> = in_degree
57 .iter()
58 .filter(|(_, °)| deg == 0)
59 .map(|(&k, _)| k)
60 .collect();
61 let mut result: Vec<TypeId> = Vec::new();
62 while let Some(node) = queue.pop_front() {
63 result.push(node);
64 for (child, parents) in &self.edges {
65 if parents.iter().any(|p| *p == node && *p != *child) {
66 let deg = in_degree.entry(*child).or_insert(0);
67 if *deg > 0 {
68 *deg -= 1;
69 }
70 if *deg == 0 && !result.contains(child) && !queue.contains(child) {
71 queue.push_back(*child);
72 }
73 }
74 }
75 }
76 for node in &self.nodes {
77 if !result.contains(node) {
78 result.push(*node);
79 }
80 }
81 result
82 }
83
84 pub fn deletion_order(&self) -> Vec<TypeId> {
86 let mut order = self.topological_sort();
87 order.reverse();
88 order
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn empty_graph_returns_empty() {
98 let metas: HashMap<TypeId, EntityTypeMeta> = HashMap::new();
99 let graph = DependencyGraph::build(&metas);
100 assert!(graph.topological_sort().is_empty());
101 }
102
103 #[test]
104 fn deletion_order_is_reverse_of_insert() {
105 let metas: HashMap<TypeId, EntityTypeMeta> = HashMap::new();
106 let graph = DependencyGraph::build(&metas);
107 let insert = graph.topological_sort();
108 let delete = graph.deletion_order();
109 assert_eq!(delete, insert.into_iter().rev().collect::<Vec<_>>());
110 }
111}