fkl_mir/strategy/
context_map.rs1use std::fmt::Display;
2use serde::Deserialize;
3use serde::Serialize;
4
5use crate::{BoundedContext, ConnectionDirection, ContextRelation, LayeredArchitecture, SourceSets, Step};
6use crate::environment::Environment;
7use crate::implementation::Implementation;
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
19pub struct ContextMap {
20 pub name: String,
21 pub state: ContextState,
22 pub contexts: Vec<BoundedContext>,
23 pub relations: Vec<ContextRelation>,
24 pub implementations: Vec<Implementation>,
25 pub layered: Option<LayeredArchitecture>,
26 pub source_sets: Option<SourceSets>,
27 pub envs: Vec<Environment>
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31pub enum ContextState {
32 AsIs,
33 ToBe,
34}
35
36impl Default for ContextState {
37 fn default() -> Self {
38 ContextState::ToBe
39 }
40}
41
42impl Display for ContextMap {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 writeln!(f, "ContextMap({})", self.name)?;
45 for relation in &self.relations {
46 let rel = match relation.connection_type {
47 ConnectionDirection::Undirected => "-",
48 ConnectionDirection::PositiveDirected => "->",
49 ConnectionDirection::NegativeDirected => "<-",
50 ConnectionDirection::BiDirected => "<->",
51 };
52 writeln!(f, " Relation({} {} {}) ", relation.source, rel, relation.target)?;
53 }
54
55 for context in &self.contexts {
56 writeln!(f, " BoundedContext({})", context.name)?;
57 for aggregate in &context.aggregates {
58 writeln!(f, " Aggregate({})", aggregate.name)?;
59 for entity in &aggregate.entities {
60 writeln!(f, " Entity({})", entity.name)?;
61 entity.fields.iter().for_each(|field| {
62 writeln!(f, " Field({})", field.name).unwrap();
63 });
64 }
65 }
66 }
67
68 for imp in &self.implementations {
69 match imp {
70 Implementation::PublishHttpApi(api) => {
71 writeln!(f, " PublishHttpApi({})", api.name)?;
72 writeln!(f, " {:?} Path({})", api.endpoint.method, api.endpoint.path)?;
73
74 if let Some(request) = &api.endpoint.request {
75 writeln!(f, " Request: {}", request.name)?;
76 }
77
78 if let Some(response) = &api.endpoint.response {
79 writeln!(f, " Response: {}", response.name)?;
80 }
81
82 api.flow.iter().for_each(|flow| {
83 writeln!(f, " Flow").unwrap();
84 flow.steps.iter().for_each(|step| {
85 match step {
86 Step::MethodCall(call) => {
87 writeln!(f, " MethodCall({})", call.name).unwrap();
88 }
89 Step::Message(msg) => {
90 writeln!(f, " Message({})", msg.from).unwrap();
91 }
92 Step::RpcCall(_) => {}
93 }
94 });
95 });
96 }
97 Implementation::PublishEvent => {}
98 Implementation::PublishMessage => {}
99 }
100 }
101
102 self.layered.as_ref().map(|layered| {
103 writeln!(f, " LayeredArchitecture({})", layered.name).unwrap();
104 for layer in &layered.layers {
105 writeln!(f, " Layer {} (\"{}\")", layer.name, layer.package).unwrap();
106 }
107 });
108
109 Ok(())
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use crate::ContextMap;
116 use crate::{Aggregate, BoundedContext, Entity};
117
118 #[test]
119 fn display_context_map() {
120 let context_map = ContextMap {
121 name: "Ticket".to_string(),
122 state: Default::default(),
123 contexts: vec![BoundedContext {
124 name: "TicketContext".to_string(),
125 aggregates: vec![
126 Aggregate {
127 name: "TicketAggregate".to_string(),
128 description: "".to_string(),
129 entities: vec![Entity {
130 name: "TicketEntity".to_string(),
131 description: "".to_string(),
132 is_aggregate_root: false,
133 identify: Default::default(),
134 fields: vec![],
135 }],
136 }
137 ],
138 }],
139 relations: vec![],
140 implementations: vec![],
141 layered: None,
142 source_sets: None,
143 envs: vec![]
144 };
145 let output = format!("{}", context_map);
146 assert_eq!(output, r#"ContextMap(Ticket)
147 BoundedContext(TicketContext)
148 Aggregate(TicketAggregate)
149 Entity(TicketEntity)
150"#);
151 }
152}