Skip to content

Commit

Permalink
feat(fkl): add aggregate support
Browse files Browse the repository at this point in the history
  • Loading branch information
phodal committed Sep 24, 2022
1 parent 30fd54d commit 64605d3
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 30 deletions.
4 changes: 4 additions & 0 deletions crates/fkl_parser/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ pub mod binding;
pub use strategy::context_map::*;
pub use strategy::domain::*;
pub use strategy::bounded_context::*;
pub use tactic::aggregate::*;
pub use tactic::entity::*;
pub use tactic::value_object::*;
pub use tactic::domain_object::*;
8 changes: 6 additions & 2 deletions crates/fkl_parser/src/mir/strategy/bounded_context.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
use std::fmt::{Display, Formatter};

use serde::Deserialize;
use serde::Serialize;
use std::fmt::{Display, Formatter};

use crate::mir::tactic::aggregate::Aggregate;

// # Bounded Context
// A description of a boundary (typically a subsystem, or the work of a particular team) within
// which a particular model is defined and applicable.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct BoundedContext {
pub name: String,
pub aggregates: Vec<Aggregate>,
}

impl BoundedContext {
pub fn new(name: &str) -> Self {
BoundedContext { name: name.to_string() }
BoundedContext { name: name.to_string(), aggregates: vec![] }
}
}

Expand Down
8 changes: 8 additions & 0 deletions crates/fkl_parser/src/mir/tactic/aggregate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use serde::Deserialize;
use serde::Serialize;
use crate::mir::tactic::entity::Entity;

// Cluster the entities and value objects into aggregates and define boundaries around each.
// Choose one entity to be the root of each aggregate, and allow external objects to hold
Expand All @@ -10,5 +11,12 @@ use serde::Serialize;
pub struct Aggregate {
pub name: String,
pub description: String,
pub entities: Vec<Entity>,
}

impl Aggregate {
pub fn new(name: &str) -> Self {
Aggregate { name: name.to_string(), description: "".to_string(), entities: vec![] }
}
}

12 changes: 11 additions & 1 deletion crates/fkl_parser/src/mir/tactic/entity.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
use serde::Deserialize;
use serde::Serialize;

use crate::mir::tactic::block::Field;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Entity {
pub name: String,
pub name: String,
pub description: String,
pub is_aggregate_root: bool,
pub identify: Field,
pub fields: Vec<Field>,
}
4 changes: 4 additions & 0 deletions crates/fkl_parser/src/mir/tactic/service.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use serde::Deserialize;
use serde::Serialize;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct Service {

}
2 changes: 1 addition & 1 deletion crates/fkl_parser/src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub struct ContextMapDecl {
pub struct BoundedContextDecl {
pub name: String,
pub aggregates: Vec<AggregateDecl>,
pub use_domain_objects: Vec<UsedDomainObject>,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -116,7 +117,6 @@ pub struct ApplicationServiceDecl {
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct AggregateDecl {
pub name: String,
pub is_root: bool,
pub inline_doc: String,
pub used_domain_objects: Vec<UsedDomainObject>,
pub entities: Vec<EntityDecl>,
Expand Down
12 changes: 4 additions & 8 deletions crates/fkl_parser/src/parser/fkl.pest
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ context_map_decl = {
}

context_decl = {
"Context" ~ identifier ~ "{" ~ (module_decl | aggregate_decl | inline_doc)* ~ "}"
"Context" ~ identifier ~ "{" ~ (module_decl | aggregate_decl | use_domain_object_decl | inline_doc)* ~ "}"
}

context_node_decl = {
"context" ~ identifier
("Context" | "context") ~ identifier
}

context_node_rel = {
Expand Down Expand Up @@ -63,7 +63,7 @@ aggregate_decl = {
}

use_domain_object_decl = {
("Concept" | "Entity" | "VO" | "ValueObject" ) ~ identifier ~ ("," ~ identifier)* ~ ";"
("Concept" | "Entity" | "VO" | "ValueObject" | "Aggregate" ) ~ identifier ~ ("," ~ identifier)* ~ ";"
}

entity_decl = {
Expand Down Expand Up @@ -108,11 +108,7 @@ param_type = {
}

component_decl = {
"Component" ~ identifier ~ "{" ~ (attr_decl | inline_doc | use_aggregate )* ~ "}"
}

use_aggregate = {
"Aggregate" ~ identifier ~ ";"?
"Component" ~ identifier ~ "{" ~ (attr_decl | inline_doc | use_domain_object_decl )* ~ "}"
}

attr_decl = {
Expand Down
18 changes: 11 additions & 7 deletions crates/fkl_parser/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fn consume_context_map(pair: Pair<Rule>) -> ContextMapDecl {
context_decl_map.insert(context_name.clone(), BoundedContextDecl {
name: context_name,
aggregates: vec![],
use_domain_objects: vec![],
});
}
Rule::rel_symbol => {
Expand Down Expand Up @@ -176,6 +177,9 @@ fn consume_context(pair: Pair<Rule>) -> BoundedContextDecl {
Rule::aggregate_decl => {
context.aggregates.push(consume_aggregate(p));
}
Rule::use_domain_object_decl => {
context.use_domain_objects.push(consume_use_domain_object(p));
}
_ => println!("unreachable context rule: {:?}", p.as_rule())
};
}
Expand Down Expand Up @@ -405,16 +409,18 @@ Context ShoppingCarContext {
assert_eq!(decls[0], FklDeclaration::ContextMap(ContextMapDecl {
name: Identifier {
name: "".to_string(),
loc: Default::default()
loc: Default::default(),
},
contexts: vec![
BoundedContextDecl {
name: "MallContext".to_string(),
aggregates: vec![],
use_domain_objects: vec![],
},
BoundedContextDecl {
name: "ShoppingCarContext".to_string(),
aggregates: vec![],
use_domain_objects: vec![],
},
],
relations: vec![
Expand All @@ -436,7 +442,6 @@ just for test

assert_eq!(decls[0], FklDeclaration::Aggregate(AggregateDecl {
name: "Sample".to_string(),
is_root: false,
inline_doc: r#" inline doc sample
just for test
"#.to_string(),
Expand All @@ -458,7 +463,6 @@ Aggregate ShoppingCart {

assert_eq!(decls[0], FklDeclaration::Aggregate(AggregateDecl {
name: "ShoppingCart".to_string(),
is_root: false,
inline_doc: "".to_string(),
used_domain_objects: vec![],
entities: vec![EntityDecl {
Expand Down Expand Up @@ -640,7 +644,6 @@ Entity SalesPerson {
aggregates: vec![
AggregateDecl {
name: "Cart".to_string(),
is_root: false,
inline_doc: "".to_string(),
used_domain_objects: vec![],
entities: vec![EntityDecl {
Expand Down Expand Up @@ -690,6 +693,7 @@ Entity SalesPerson {
value_objects: vec![],
}
],
use_domain_objects: vec![],
}));
}

Expand Down Expand Up @@ -728,11 +732,11 @@ Component SalesComponent {
let except = FklDeclaration::ContextMap(ContextMapDecl {
name: Identifier {
name: "Mall".to_string(),
loc: Loc(11, 15)
loc: Loc(11, 15),
},
contexts: vec![
BoundedContextDecl { name: "OrderContext".to_string(), aggregates: vec![] },
BoundedContextDecl { name: "SalesContext".to_string(), aggregates: vec![] },
BoundedContextDecl { name: "OrderContext".to_string(), aggregates: vec![], use_domain_objects: vec![] },
BoundedContextDecl { name: "SalesContext".to_string(), aggregates: vec![], use_domain_objects: vec![] },
],
relations: vec![ContextRelation {
source: "SalesContext".to_string(),
Expand Down
46 changes: 41 additions & 5 deletions crates/fkl_parser/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
mod test {
use crate::mir;
use crate::mir::{BoundedContext, ContextRelation, ContextState};
use crate::mir::{Aggregate, BoundedContext, ContextRelation, ContextState};
use crate::mir::ConnectionDirection::PositiveDirected;
use crate::parse;

Expand All @@ -14,6 +14,10 @@ ContextMap TicketBooking {
Reservation -> User;
}
Context Reservation {
Aggregate Reservation;
}
Aggregate Reservation {
Entity Ticket, Reservation;
}
Expand All @@ -36,6 +40,10 @@ Entity Reservation {
Entity Ticket {}
Context Cinema {
Aggregate Cinema;
}
Aggregate Cinema {
Entity Cinema, ScreeningRoom, Seat;
}
Expand All @@ -44,6 +52,10 @@ Entity Cinema { }
Entity ScreeningRoom { }
Entity Seat { }
Context Movie {
Aggregate Movie;
}
Aggregate Movie {
Entity Movie, Actor, Publisher;
}
Expand All @@ -52,6 +64,10 @@ Entity Movie { }
Entity Actor { }
Entity Publisher { }
Context User {
Aggregate User;
}
Aggregate User {
Entity User;
}
Expand Down Expand Up @@ -86,10 +102,30 @@ ValueObject Notifications { }
name: "TicketBooking".to_string(),
state: ContextState::ToBe,
contexts: vec![
BoundedContext { name: "Cinema".to_string() },
BoundedContext { name: "Movie".to_string() },
BoundedContext { name: "Reservation".to_string() },
BoundedContext { name: "User".to_string() }],
BoundedContext {
name: "Cinema".to_string(),
aggregates: vec![
Aggregate { name: "Cinema".to_string(), description: "".to_string(), entities: vec![] }
],
},
BoundedContext {
name: "Movie".to_string(),
aggregates: vec![
Aggregate { name: "Movie".to_string(), description: "".to_string(), entities: vec![] }
],
},
BoundedContext {
name: "Reservation".to_string(),
aggregates: vec![
Aggregate { name: "Reservation".to_string(), description: "".to_string(), entities: vec![] }
],
},
BoundedContext {
name: "User".to_string(),
aggregates: vec![
Aggregate { name: "User".to_string(), description: "".to_string(), entities: vec![] }
],
}],
relations: vec![
ContextRelation {
source: "Reservation".to_string(),
Expand Down
35 changes: 29 additions & 6 deletions crates/fkl_parser/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use indexmap::IndexMap;

use crate::{ContextMap, mir, ParseError};
use crate::mir::{BoundedContext, ConnectionDirection, ContextRelationType};
use crate::mir::tactic::aggregate::Aggregate;
use crate::parser::ast::{AggregateDecl, FklDeclaration, RelationDirection};
use crate::parser::parse as ast_parse;
use crate::parser::ast::{FklDeclaration, RelationDirection};

pub struct MirTransform {
pub context_map_name: String,
pub contexts: IndexMap<String, BoundedContext>,
pub aggregates: IndexMap<String, Aggregate>,
pub relations: Vec<mir::ContextRelation>,
}

Expand All @@ -16,6 +18,7 @@ impl MirTransform {
let mut transform = MirTransform {
context_map_name: "".to_string(),
contexts: Default::default(),
aggregates: Default::default(),
relations: vec![],
};

Expand All @@ -35,8 +38,8 @@ impl MirTransform {
}

fn lower_decls(&mut self, decls: Vec<FklDeclaration>) {
decls.iter().for_each(|decl| {
match decl {
decls.iter().for_each(|declaration| {
match declaration {
FklDeclaration::None => {}
FklDeclaration::ContextMap(context_map) => {
self.context_map_name = context_map.name.name.clone();
Expand All @@ -58,11 +61,17 @@ impl MirTransform {
});
}
FklDeclaration::BoundedContext(bc) => {
let bounded_context = mir::BoundedContext::new(&bc.name);
let mut bounded_context = mir::BoundedContext::new(&bc.name);
bc.use_domain_objects.iter().for_each(|domain_object| {
let aggregate = Aggregate::new(&domain_object.name);
bounded_context.aggregates.push(aggregate);
});
self.contexts.insert(bounded_context.name.clone(), bounded_context);
}
FklDeclaration::Domain(_) => {}
FklDeclaration::Aggregate(_) => {}
FklDeclaration::Aggregate(decl) => {
self.transform_aggregate(&decl);
}
FklDeclaration::DomainService(_) => {}
FklDeclaration::ApplicationService(_) => {}
FklDeclaration::Entity(_) => {}
Expand All @@ -71,6 +80,20 @@ impl MirTransform {
}
});
}

fn transform_aggregate(&mut self, decl: &AggregateDecl) -> mir::Aggregate {
let mut aggregate = mir::Aggregate::new(&decl.name);
self.aggregates.insert(aggregate.name.clone(), aggregate.clone());
// decl.entities.iter().for_each(|entity| {
// });

aggregate
}

// fn transform_entity(decl: &EntityDecl) -> mir::Entity {
// let entity = mir::Entity::new(&decl.name);
// entity
// }
}

fn transform_connection(rd: &RelationDirection) -> ConnectionDirection {
Expand All @@ -84,8 +107,8 @@ fn transform_connection(rd: &RelationDirection) -> ConnectionDirection {

#[cfg(test)]
mod tests {
use crate::mir::ConnectionDirection::PositiveDirected;
use crate::mir::{ContextRelation, ContextRelationType};
use crate::mir::ConnectionDirection::PositiveDirected;
use crate::transform::MirTransform;

#[test]
Expand Down

0 comments on commit 64605d3

Please sign in to comment.