armature_admin/
registry.rs1use crate::model::ModelDefinition;
4use std::collections::HashMap;
5
6#[derive(Debug, Default)]
8pub struct ModelRegistry {
9 models: HashMap<String, ModelDefinition>,
11 order: Vec<String>,
13 groups: HashMap<String, Vec<String>>,
15}
16
17impl ModelRegistry {
18 pub fn new() -> Self {
20 Self {
21 models: HashMap::new(),
22 order: Vec::new(),
23 groups: HashMap::new(),
24 }
25 }
26
27 pub fn register(&mut self, model: ModelDefinition) {
29 let name = model.name.clone();
30 self.order.push(name.clone());
31 self.models.insert(name, model);
32 }
33
34 pub fn register_in_group(&mut self, group: impl Into<String>, model: ModelDefinition) {
36 let group = group.into();
37 let name = model.name.clone();
38
39 self.models.insert(name.clone(), model);
40
41 if !self.order.contains(&name) {
42 self.order.push(name.clone());
43 }
44
45 self.groups
46 .entry(group)
47 .or_default()
48 .push(name);
49 }
50
51 pub fn get(&self, name: &str) -> Option<&ModelDefinition> {
53 self.models.get(name)
54 }
55
56 pub fn all(&self) -> Vec<&ModelDefinition> {
58 self.order
59 .iter()
60 .filter_map(|name| self.models.get(name))
61 .collect()
62 }
63
64 pub fn names(&self) -> &[String] {
66 &self.order
67 }
68
69 pub fn group(&self, name: &str) -> Vec<&ModelDefinition> {
71 self.groups
72 .get(name)
73 .map(|names| {
74 names
75 .iter()
76 .filter_map(|n| self.models.get(n))
77 .collect()
78 })
79 .unwrap_or_default()
80 }
81
82 pub fn groups(&self) -> &HashMap<String, Vec<String>> {
84 &self.groups
85 }
86
87 pub fn contains(&self, name: &str) -> bool {
89 self.models.contains_key(name)
90 }
91
92 pub fn count(&self) -> usize {
94 self.models.len()
95 }
96
97 pub fn unregister(&mut self, name: &str) -> Option<ModelDefinition> {
99 self.order.retain(|n| n != name);
100 for group in self.groups.values_mut() {
101 group.retain(|n| n != name);
102 }
103 self.models.remove(name)
104 }
105
106 pub fn sidebar_items(&self) -> Vec<SidebarItem> {
108 if !self.groups.is_empty() {
110 let mut items = Vec::new();
111 let mut ungrouped = Vec::new();
112
113 for (group_name, model_names) in &self.groups {
115 let models: Vec<_> = model_names
116 .iter()
117 .filter_map(|n| self.models.get(n))
118 .map(|m| SidebarItem::Model {
119 name: m.name.clone(),
120 label: m.verbose_name.clone(),
121 icon: m.icon.clone(),
122 })
123 .collect();
124
125 if !models.is_empty() {
126 items.push(SidebarItem::Group {
127 name: group_name.clone(),
128 items: models,
129 });
130 }
131 }
132
133 for name in &self.order {
135 let in_group = self.groups.values().any(|g| g.contains(name));
136 if !in_group {
137 if let Some(model) = self.models.get(name) {
138 ungrouped.push(SidebarItem::Model {
139 name: model.name.clone(),
140 label: model.verbose_name.clone(),
141 icon: model.icon.clone(),
142 });
143 }
144 }
145 }
146
147 items.extend(ungrouped);
148 items
149 } else {
150 self.order
152 .iter()
153 .filter_map(|name| self.models.get(name))
154 .map(|m| SidebarItem::Model {
155 name: m.name.clone(),
156 label: m.verbose_name.clone(),
157 icon: m.icon.clone(),
158 })
159 .collect()
160 }
161 }
162}
163
164#[derive(Debug, Clone)]
166pub enum SidebarItem {
167 Model {
169 name: String,
170 label: String,
171 icon: Option<String>,
172 },
173 Group {
175 name: String,
176 items: Vec<SidebarItem>,
177 },
178 Divider,
180 Link {
182 label: String,
183 url: String,
184 icon: Option<String>,
185 },
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::field::{FieldDefinition, FieldType};
192
193 #[test]
194 fn test_registry() {
195 let mut registry = ModelRegistry::new();
196
197 let user = ModelDefinition::builder("user")
198 .id_field()
199 .field(FieldDefinition::new("name", FieldType::String))
200 .build();
201
202 let post = ModelDefinition::builder("post")
203 .id_field()
204 .field(FieldDefinition::new("title", FieldType::String))
205 .build();
206
207 registry.register(user);
208 registry.register(post);
209
210 assert_eq!(registry.count(), 2);
211 assert!(registry.contains("user"));
212 assert!(registry.contains("post"));
213 assert!(!registry.contains("comment"));
214 }
215
216 #[test]
217 fn test_registry_groups() {
218 let mut registry = ModelRegistry::new();
219
220 let user = ModelDefinition::builder("user")
221 .id_field()
222 .build();
223
224 let role = ModelDefinition::builder("role")
225 .id_field()
226 .build();
227
228 registry.register_in_group("Auth", user);
229 registry.register_in_group("Auth", role);
230
231 let auth_models = registry.group("Auth");
232 assert_eq!(auth_models.len(), 2);
233 }
234}
235