1use crate::patterns::Pattern;
2use crate::policy::{Policy, Severity, Violation};
3use crate::primitives::{
4 ConceptChange, Entity, Flow, Instance, MappingContract, Metric, ProjectionContract,
5 RelationType, Resource, ResourceInstance, Role,
6};
7use crate::validation_result::ValidationResult;
8use crate::ConceptId;
9use indexmap::IndexMap;
10use serde::{Deserialize, Serialize};
11
12pub mod to_ast;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct GraphConfig {
17 pub use_three_valued_logic: bool,
20}
21
22impl Default for GraphConfig {
23 fn default() -> Self {
24 Self {
25 use_three_valued_logic: true,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct Graph {
33 entities: IndexMap<ConceptId, Entity>,
34 roles: IndexMap<ConceptId, Role>,
35 resources: IndexMap<ConceptId, Resource>,
36 flows: IndexMap<ConceptId, Flow>,
37 relations: IndexMap<ConceptId, RelationType>,
38 instances: IndexMap<ConceptId, ResourceInstance>,
39 entity_instances: IndexMap<ConceptId, Instance>,
41 policies: IndexMap<ConceptId, Policy>,
42 #[serde(default)]
43 patterns: IndexMap<ConceptId, Pattern>,
44 #[serde(default)]
45 concept_changes: IndexMap<ConceptId, ConceptChange>,
46 #[serde(default)]
47 metrics: IndexMap<ConceptId, Metric>,
48 #[serde(default)]
49 mappings: IndexMap<ConceptId, MappingContract>,
50 #[serde(default)]
51 projections: IndexMap<ConceptId, ProjectionContract>,
52 #[serde(default)]
53 entity_roles: IndexMap<ConceptId, Vec<ConceptId>>,
54 #[serde(default)]
55 config: GraphConfig,
56}
57
58impl Graph {
59 pub fn new() -> Self {
60 Self::default()
61 }
62
63 pub fn is_empty(&self) -> bool {
64 self.entities.is_empty()
65 && self.roles.is_empty()
66 && self.resources.is_empty()
67 && self.flows.is_empty()
68 && self.relations.is_empty()
69 && self.instances.is_empty()
70 && self.entity_instances.is_empty()
71 && self.policies.is_empty()
72 && self.patterns.is_empty()
73 && self.concept_changes.is_empty()
74 && self.concept_changes.is_empty()
75 && self.metrics.is_empty()
76 && self.mappings.is_empty()
77 && self.projections.is_empty()
78 }
79
80 pub fn set_evaluation_mode(&mut self, use_three_valued_logic: bool) {
84 self.config.use_three_valued_logic = use_three_valued_logic;
85 }
86
87 pub fn use_three_valued_logic(&self) -> bool {
89 self.config.use_three_valued_logic
90 }
91
92 pub fn config(&self) -> &GraphConfig {
93 &self.config
94 }
95
96 pub fn config_mut(&mut self) -> &mut GraphConfig {
97 &mut self.config
98 }
99
100 pub fn entity_count(&self) -> usize {
101 self.entities.len()
102 }
103
104 pub fn add_entity(&mut self, entity: Entity) -> Result<(), String> {
105 let id = entity.id().clone();
106 if self.entities.contains_key(&id) {
107 return Err(format!("Entity with ID {} already exists", id));
108 }
109 self.entities.insert(id, entity);
110 Ok(())
111 }
112
113 pub fn has_entity(&self, id: &ConceptId) -> bool {
114 self.entities.contains_key(id)
115 }
116
117 pub fn get_entity(&self, id: &ConceptId) -> Option<&Entity> {
118 self.entities.get(id)
119 }
120
121 pub fn get_entity_mut(&mut self, id: &ConceptId) -> Option<&mut Entity> {
125 self.entities.get_mut(id)
126 }
127
128 pub fn remove_entity(&mut self, id: &ConceptId) -> Result<Entity, String> {
129 let referencing_flows: Vec<String> = self
131 .flows
132 .values()
133 .filter(|flow| flow.from_id() == id || flow.to_id() == id)
134 .map(|flow| flow.id().to_string())
135 .collect();
136
137 let referencing_instances: Vec<String> = self
139 .instances
140 .values()
141 .filter(|instance| instance.entity_id() == id)
142 .map(|instance| instance.id().to_string())
143 .collect();
144
145 if !referencing_flows.is_empty() || !referencing_instances.is_empty() {
146 let mut error_msg = format!("Cannot remove entity {} because it is referenced", id);
147 if !referencing_flows.is_empty() {
148 error_msg.push_str(&format!(" by flows: {}", referencing_flows.join(", ")));
149 }
150 if !referencing_instances.is_empty() {
151 error_msg.push_str(&format!(
152 " by instances: {}",
153 referencing_instances.join(", ")
154 ));
155 }
156 return Err(error_msg);
157 }
158
159 self.entities
160 .shift_remove(id)
161 .ok_or_else(|| format!("Entity with ID {} not found", id))
162 }
163
164 pub fn role_count(&self) -> usize {
165 self.roles.len()
166 }
167
168 pub fn add_role(&mut self, role: Role) -> Result<(), String> {
169 let id = role.id().clone();
170 if self.roles.contains_key(&id) {
171 return Err(format!("Role with ID {} already exists", id));
172 }
173 self.roles.insert(id, role);
174 Ok(())
175 }
176
177 pub fn get_role(&self, id: &ConceptId) -> Option<&Role> {
178 self.roles.get(id)
179 }
180
181 pub fn has_role(&self, id: &ConceptId) -> bool {
182 self.roles.contains_key(id)
183 }
184
185 pub fn assign_role_to_entity(
186 &mut self,
187 entity_id: ConceptId,
188 role_id: ConceptId,
189 ) -> Result<(), String> {
190 if !self.entities.contains_key(&entity_id) {
191 return Err(format!("Entity with ID {} not found", entity_id));
192 }
193 if !self.roles.contains_key(&role_id) {
194 return Err(format!("Role with ID {} not found", role_id));
195 }
196
197 let roles = self.entity_roles.entry(entity_id).or_default();
198 if !roles.contains(&role_id) {
199 roles.push(role_id);
200 }
201 Ok(())
202 }
203
204 pub fn roles_for_entity(&self, entity_id: &ConceptId) -> Option<&Vec<ConceptId>> {
205 self.entity_roles.get(entity_id)
206 }
207
208 pub fn role_names_for_entity(&self, entity_id: &ConceptId) -> Vec<String> {
209 self.entity_roles
210 .get(entity_id)
211 .into_iter()
212 .flat_map(|roles| roles.iter())
213 .filter_map(|role_id| self.roles.get(role_id))
214 .map(|role| role.name().to_string())
215 .collect()
216 }
217
218 pub fn resource_count(&self) -> usize {
219 self.resources.len()
220 }
221
222 pub fn add_resource(&mut self, resource: Resource) -> Result<(), String> {
223 let id = resource.id().clone();
224 if self.resources.contains_key(&id) {
225 return Err(format!("Resource with ID {} already exists", id));
226 }
227 self.resources.insert(id, resource);
228 Ok(())
229 }
230
231 pub fn has_resource(&self, id: &ConceptId) -> bool {
232 self.resources.contains_key(id)
233 }
234
235 pub fn get_resource(&self, id: &ConceptId) -> Option<&Resource> {
236 self.resources.get(id)
237 }
238
239 pub fn remove_resource(&mut self, id: &ConceptId) -> Result<Resource, String> {
240 let referencing_flows: Vec<String> = self
242 .flows
243 .values()
244 .filter(|flow| flow.resource_id() == id)
245 .map(|flow| flow.id().to_string())
246 .collect();
247
248 let referencing_instances: Vec<String> = self
250 .instances
251 .values()
252 .filter(|instance| instance.resource_id() == id)
253 .map(|instance| instance.id().to_string())
254 .collect();
255
256 if !referencing_flows.is_empty() || !referencing_instances.is_empty() {
257 let mut error_msg = format!("Cannot remove resource {} because it is referenced", id);
258 if !referencing_flows.is_empty() {
259 error_msg.push_str(&format!(" by flows: {}", referencing_flows.join(", ")));
260 }
261 if !referencing_instances.is_empty() {
262 error_msg.push_str(&format!(
263 " by instances: {}",
264 referencing_instances.join(", ")
265 ));
266 }
267 return Err(error_msg);
268 }
269
270 self.resources
271 .shift_remove(id)
272 .ok_or_else(|| format!("Resource with ID {} not found", id))
273 }
274
275 pub fn flow_count(&self) -> usize {
276 self.flows.len()
277 }
278
279 pub fn pattern_count(&self) -> usize {
280 self.patterns.len()
281 }
282
283 pub fn relation_count(&self) -> usize {
284 self.relations.len()
285 }
286
287 pub fn add_relation_type(&mut self, relation: RelationType) -> Result<(), String> {
288 let id = relation.id().clone();
289 if self.relations.contains_key(&id) {
290 return Err(format!("Relation with ID {} already exists", id));
291 }
292 self.relations.insert(id, relation);
293 Ok(())
294 }
295
296 pub fn all_relations(&self) -> Vec<&RelationType> {
297 self.relations.values().collect()
298 }
299
300 pub fn add_flow(&mut self, flow: Flow) -> Result<(), String> {
301 let id = flow.id().clone();
302 if self.flows.contains_key(&id) {
303 return Err(format!("Flow with ID {} already exists", id));
304 }
305 if !self.entities.contains_key(flow.from_id()) {
306 return Err("Source entity not found".to_string());
307 }
308 if !self.entities.contains_key(flow.to_id()) {
309 return Err("Target entity not found".to_string());
310 }
311 if !self.resources.contains_key(flow.resource_id()) {
312 return Err("Resource not found".to_string());
313 }
314 self.flows.insert(id, flow);
315 Ok(())
316 }
317
318 pub fn add_pattern(&mut self, pattern: Pattern) -> Result<(), String> {
319 let id = pattern.id().clone();
320 if self.patterns.contains_key(&id) {
321 return Err(format!("Pattern with ID {} already exists", id));
322 }
323
324 if self.patterns.values().any(|existing| {
325 existing.name() == pattern.name() && existing.namespace() == pattern.namespace()
326 }) {
327 return Err(format!(
328 "Pattern '{}' already declared in namespace '{}'",
329 pattern.name(),
330 pattern.namespace()
331 ));
332 }
333
334 self.patterns.insert(id, pattern);
335 Ok(())
336 }
337
338 pub fn add_concept_change(&mut self, change: ConceptChange) -> Result<(), String> {
339 let id = change.id().clone();
340 if self.concept_changes.contains_key(&id) {
341 return Err(format!("ConceptChange with ID {} already exists", id));
342 }
343 self.concept_changes.insert(id, change);
344 Ok(())
345 }
346
347 pub fn get_concept_change(&self, id: &ConceptId) -> Option<&ConceptChange> {
348 self.concept_changes.get(id)
349 }
350
351 pub fn all_concept_changes(&self) -> Vec<&ConceptChange> {
352 self.concept_changes.values().collect()
353 }
354
355 pub fn has_flow(&self, id: &ConceptId) -> bool {
356 self.flows.contains_key(id)
357 }
358
359 pub fn get_flow(&self, id: &ConceptId) -> Option<&Flow> {
360 self.flows.get(id)
361 }
362
363 pub fn remove_flow(&mut self, id: &ConceptId) -> Result<Flow, String> {
364 self.flows
365 .shift_remove(id)
366 .ok_or_else(|| format!("Flow with ID {} not found", id))
367 }
368
369 pub fn instance_count(&self) -> usize {
370 self.instances.len()
371 }
372
373 pub fn add_instance(&mut self, instance: ResourceInstance) -> Result<(), String> {
374 let id = instance.id().clone();
375 if self.instances.contains_key(&id) {
376 return Err(format!("Instance with ID {} already exists", id));
377 }
378 if !self.entities.contains_key(instance.entity_id()) {
379 return Err("Entity not found".to_string());
380 }
381 if !self.resources.contains_key(instance.resource_id()) {
382 return Err("Resource not found".to_string());
383 }
384 self.instances.insert(id, instance);
385 Ok(())
386 }
387
388 pub fn add_association(
392 &mut self,
393 owner: &ConceptId,
394 owned: &ConceptId,
395 rel_type: &str,
396 ) -> Result<(), String> {
397 if !self.entities.contains_key(owner) {
398 return Err("Source entity not found".to_string());
399 }
400 if !self.entities.contains_key(owned) {
401 return Err("Destination entity not found".to_string());
402 }
403
404 let owned_str = owned.to_string();
405 let rel_type_str = rel_type.to_string();
406
407 if let Some(entity) = self.entities.get_mut(owner) {
409 use serde_json::{json, Value};
410 let mut associations: Value = entity
411 .get_attribute("associations")
412 .cloned()
413 .unwrap_or_else(|| json!([]));
414
415 if let Value::Array(arr) = &mut associations {
416 arr.push(json!({"type": rel_type_str, "target": owned_str}));
417 } else {
418 associations = json!([ {"type": rel_type_str, "target": owned_str} ]);
420 }
421
422 entity.set_attribute("associations", associations);
423 Ok(())
424 } else {
425 Err("Failed to retrieve entity for association".to_string())
426 }
427 }
428
429 pub fn has_instance(&self, id: &ConceptId) -> bool {
430 self.instances.contains_key(id)
431 }
432
433 pub fn get_instance(&self, id: &ConceptId) -> Option<&ResourceInstance> {
434 self.instances.get(id)
435 }
436
437 pub fn remove_instance(&mut self, id: &ConceptId) -> Result<ResourceInstance, String> {
438 self.instances
439 .shift_remove(id)
440 .ok_or_else(|| format!("Instance with ID {} not found", id))
441 }
442
443 pub fn entity_instance_count(&self) -> usize {
445 self.entity_instances.len()
446 }
447
448 pub fn add_entity_instance(&mut self, instance: Instance) -> Result<(), String> {
449 let id = instance.id().clone();
450 if self.entity_instances.contains_key(&id) {
451 return Err(format!(
452 "Entity instance '{}' already exists",
453 instance.name()
454 ));
455 }
456 if self.find_entity_instance_by_name(instance.name()).is_some() {
457 return Err(format!(
458 "Entity instance '{}' already exists",
459 instance.name()
460 ));
461 }
462
463 let namespace = instance.namespace();
464 let entity_type = instance.entity_type();
465
466 self.find_entity_by_name_and_namespace(entity_type, namespace)
467 .ok_or_else(|| {
468 format!(
469 "Entity '{}' not found in namespace '{}'",
470 entity_type, namespace
471 )
472 })?;
473
474 self.entity_instances.insert(id, instance);
475 Ok(())
476 }
477
478 pub fn get_entity_instance(&self, name: &str) -> Option<&Instance> {
479 self.find_entity_instance_by_name(name)
480 .and_then(|id| self.entity_instances.get(&id))
481 }
482
483 pub fn get_entity_instance_mut(&mut self, name: &str) -> Option<&mut Instance> {
484 let id = self.find_entity_instance_by_name(name)?;
485 self.entity_instances.get_mut(&id)
486 }
487
488 pub fn all_entity_instances(&self) -> Vec<&Instance> {
489 self.entity_instances.values().collect()
490 }
491
492 pub fn remove_entity_instance(&mut self, name: &str) -> Result<Instance, String> {
493 let id = self
494 .find_entity_instance_by_name(name)
495 .ok_or_else(|| format!("Entity instance '{}' not found", name))?;
496
497 self.entity_instances
498 .shift_remove(&id)
499 .ok_or_else(|| format!("Entity instance '{}' not found", name))
500 }
501
502 pub fn has_entity_instance_by_id(&self, id: &ConceptId) -> bool {
503 self.entity_instances.contains_key(id)
504 }
505
506 pub fn get_entity_instance_by_id(&self, id: &ConceptId) -> Option<&Instance> {
507 self.entity_instances.get(id)
508 }
509
510 pub fn remove_entity_instance_by_id(&mut self, id: &ConceptId) -> Result<Instance, String> {
511 self.entity_instances
512 .shift_remove(id)
513 .ok_or_else(|| format!("Entity instance with id '{}' not found", id))
514 }
515
516 pub fn flows_from(&self, entity_id: &ConceptId) -> Vec<&Flow> {
517 self.flows
518 .values()
519 .filter(|flow| flow.from_id() == entity_id)
520 .collect()
521 }
522
523 pub fn flows_to(&self, entity_id: &ConceptId) -> Vec<&Flow> {
524 self.flows
525 .values()
526 .filter(|flow| flow.to_id() == entity_id)
527 .collect()
528 }
529
530 pub fn upstream_entities(&self, entity_id: &ConceptId) -> Vec<&Entity> {
531 self.flows_to(entity_id)
532 .iter()
533 .filter_map(|flow| self.get_entity(flow.from_id()))
534 .collect()
535 }
536
537 pub fn downstream_entities(&self, entity_id: &ConceptId) -> Vec<&Entity> {
538 self.flows_from(entity_id)
539 .iter()
540 .filter_map(|flow| self.get_entity(flow.to_id()))
541 .collect()
542 }
543
544 pub fn find_entity_by_name_and_namespace(
545 &self,
546 name: &str,
547 namespace: &str,
548 ) -> Option<ConceptId> {
549 self.entities
550 .iter()
551 .find(|(_, entity)| entity.name() == name && entity.namespace() == namespace)
552 .map(|(id, _)| id.clone())
553 }
554
555 pub fn find_entity_by_name(&self, name: &str) -> Option<ConceptId> {
556 self.entities
557 .iter()
558 .find(|(_, entity)| entity.name() == name)
559 .map(|(id, _)| id.clone())
560 }
561
562 pub fn find_resource_by_name(&self, name: &str) -> Option<ConceptId> {
563 self.resources
564 .iter()
565 .find(|(_, resource)| resource.name() == name)
566 .map(|(id, _)| id.clone())
567 }
568
569 pub fn find_role_by_name(&self, name: &str) -> Option<ConceptId> {
570 self.roles
571 .iter()
572 .find(|(_, role)| role.name() == name)
573 .map(|(id, _)| id.clone())
574 }
575
576 pub fn find_entity_instance_by_name(&self, name: &str) -> Option<ConceptId> {
577 self.entity_instances
578 .iter()
579 .find(|(_, instance)| instance.name() == name)
580 .map(|(id, _)| id.clone())
581 }
582
583 pub fn find_entity_instance_by_name_and_namespace(
584 &self,
585 name: &str,
586 namespace: &str,
587 ) -> Option<ConceptId> {
588 self.entity_instances
589 .iter()
590 .find(|(_, instance)| instance.name() == name && instance.namespace() == namespace)
591 .map(|(id, _)| id.clone())
592 }
593
594 pub fn find_pattern(&self, name: &str, namespace: Option<&str>) -> Option<&Pattern> {
595 if let Some(ns) = namespace {
596 if let Some((_, pattern)) = self
597 .patterns
598 .iter()
599 .find(|(_, pattern)| pattern.name() == name && pattern.namespace() == ns)
600 {
601 return Some(pattern);
602 }
603 }
604
605 self.patterns
606 .iter()
607 .find(|(_, pattern)| pattern.name() == name)
608 .map(|(_, pattern)| pattern)
609 }
610
611 pub fn all_entities(&self) -> Vec<&Entity> {
612 self.entities.values().collect()
613 }
614
615 pub fn all_roles(&self) -> Vec<&Role> {
616 self.roles.values().collect()
617 }
618
619 pub fn all_resources(&self) -> Vec<&Resource> {
620 self.resources.values().collect()
621 }
622
623 pub fn all_flows(&self) -> Vec<&Flow> {
624 self.flows.values().collect()
625 }
626
627 pub fn all_instances(&self) -> Vec<&ResourceInstance> {
628 self.instances.values().collect()
629 }
630
631 pub fn all_patterns(&self) -> Vec<&Pattern> {
632 self.patterns.values().collect()
633 }
634
635 pub fn policy_count(&self) -> usize {
636 self.policies.len()
637 }
638
639 pub fn add_policy(&mut self, policy: Policy) -> Result<(), String> {
640 let id = policy.id.clone();
641 if self.policies.contains_key(&id) {
642 return Err(format!("Policy with ID {} already exists", id));
643 }
644 self.policies.insert(id, policy);
645 Ok(())
646 }
647
648 pub fn has_policy(&self, id: &ConceptId) -> bool {
649 self.policies.contains_key(id)
650 }
651
652 pub fn get_policy(&self, id: &ConceptId) -> Option<&Policy> {
653 self.policies.get(id)
654 }
655
656 pub fn remove_policy(&mut self, id: &ConceptId) -> Result<Policy, String> {
657 self.policies
658 .shift_remove(id)
659 .ok_or_else(|| format!("Policy with ID {} not found", id))
660 }
661
662 pub fn all_policies(&self) -> Vec<&Policy> {
663 self.policies.values().collect()
664 }
665
666 pub fn metric_count(&self) -> usize {
667 self.metrics.len()
668 }
669
670 pub fn add_metric(&mut self, metric: Metric) -> Result<(), String> {
671 let id = metric.id().clone();
672 if self.metrics.contains_key(&id) {
673 return Err(format!("Metric with ID {} already exists", id));
674 }
675 self.metrics.insert(id, metric);
676 Ok(())
677 }
678
679 pub fn has_metric(&self, id: &ConceptId) -> bool {
680 self.metrics.contains_key(id)
681 }
682
683 pub fn get_metric(&self, id: &ConceptId) -> Option<&Metric> {
684 self.metrics.get(id)
685 }
686
687 pub fn all_metrics(&self) -> Vec<&Metric> {
688 self.metrics.values().collect()
689 }
690
691 pub fn mapping_count(&self) -> usize {
692 self.mappings.len()
693 }
694
695 pub fn add_mapping(&mut self, mapping: MappingContract) -> Result<(), String> {
696 let id = mapping.id().clone();
697 if self.mappings.contains_key(&id) {
698 return Err(format!("Mapping with ID {} already exists", id));
699 }
700 self.mappings.insert(id, mapping);
701 Ok(())
702 }
703
704 pub fn has_mapping(&self, id: &ConceptId) -> bool {
705 self.mappings.contains_key(id)
706 }
707
708 pub fn get_mapping(&self, id: &ConceptId) -> Option<&MappingContract> {
709 self.mappings.get(id)
710 }
711
712 pub fn all_mappings(&self) -> Vec<&MappingContract> {
713 self.mappings.values().collect()
714 }
715
716 pub fn projection_count(&self) -> usize {
717 self.projections.len()
718 }
719
720 pub fn add_projection(&mut self, projection: ProjectionContract) -> Result<(), String> {
721 let id = projection.id().clone();
722 if self.projections.contains_key(&id) {
723 return Err(format!("Projection with ID {} already exists", id));
724 }
725 self.projections.insert(id, projection);
726 Ok(())
727 }
728
729 pub fn has_projection(&self, id: &ConceptId) -> bool {
730 self.projections.contains_key(id)
731 }
732
733 pub fn get_projection(&self, id: &ConceptId) -> Option<&ProjectionContract> {
734 self.projections.get(id)
735 }
736
737 pub fn all_projections(&self) -> Vec<&ProjectionContract> {
738 self.projections.values().collect()
739 }
740
741 pub fn extend(&mut self, other: Graph) -> Result<(), String> {
745 let mut merged = self.clone();
746 merged.extend_from_graph(other)?;
747 *self = merged;
748 Ok(())
749 }
750
751 fn extend_from_graph(&mut self, other: Graph) -> Result<(), String> {
752 let Graph {
753 entities,
754 roles,
755 resources,
756 flows,
757 relations,
758 instances,
759 entity_instances,
760 policies,
761 patterns,
762 concept_changes,
763 metrics,
764 mappings,
765 projections,
766 entity_roles,
767 config: _,
768 } = other;
769
770 for entity in entities.into_values() {
771 self.add_entity(entity)?;
772 }
773
774 for role in roles.into_values() {
775 self.add_role(role)?;
776 }
777
778 for resource in resources.into_values() {
779 self.add_resource(resource)?;
780 }
781
782 for instance in instances.into_values() {
783 self.add_instance(instance)?;
784 }
785
786 for entity_instance in entity_instances.into_values() {
787 self.add_entity_instance(entity_instance)?;
788 }
789
790 for flow in flows.into_values() {
791 self.add_flow(flow)?;
792 }
793
794 for relation in relations.into_values() {
795 self.add_relation_type(relation)?;
796 }
797
798 for pattern in patterns.into_values() {
799 self.add_pattern(pattern)?;
800 }
801
802 for (entity_id, roles_for_entity) in entity_roles.into_iter() {
803 for role_id in roles_for_entity {
804 self.assign_role_to_entity(entity_id.clone(), role_id)?;
805 }
806 }
807
808 for policy in policies.into_values() {
809 self.add_policy(policy)?;
810 }
811
812 for change in concept_changes.into_values() {
813 self.add_concept_change(change)?;
814 }
815
816 for metric in metrics.into_values() {
817 self.add_metric(metric)?;
818 }
819
820 for mapping in mappings.into_values() {
821 self.add_mapping(mapping)?;
822 }
823
824 for projection in projections.into_values() {
825 self.add_projection(projection)?;
826 }
827
828 Ok(())
829 }
830
831 pub fn validate(&self) -> ValidationResult {
834 let mut all_violations: Vec<Violation> = Vec::new();
835 let use_three_valued_logic = self.config.use_three_valued_logic;
836
837 for policy in self.policies.values() {
838 match policy.evaluate_with_mode(self, use_three_valued_logic) {
839 Ok(eval) => {
840 all_violations.extend(eval.violations);
841 }
842 Err(err) => {
843 let v = Violation::new(
847 &policy.name,
848 format!("Policy evaluation failed: {}", err),
849 Severity::Error,
850 );
851 all_violations.push(v);
852 }
853 }
854 }
855
856 ValidationResult::new(self.policies.len(), all_violations)
857 }
858}