diff --git a/.circleci/config.yml b/.circleci/config.yml index f3b937a..fa63f07 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,6 +67,9 @@ jobs: - run: curl --fail -X POST http://localhost:8080/png --data-binary @result.puml -o test.png - run: ./target/release/sqlant $TEST_DATABASE_URL --legend -e --inline-puml-lib > result.puml + - run: curl --fail -X POST http://localhost:8080/png --data-binary @result.puml -o test.png + + - run: ./target/release/sqlant $TEST_DATABASE_URL --conceptual > result.puml - run: curl --fail -X POST http://localhost:8080/png --data-binary @result.puml -o test.png # Mermaid diff --git a/src/lib.rs b/src/lib.rs index e8f32fa..06f2ec4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub struct GeneratorConfigOptions { pub draw_enums: bool, pub draw_legend: bool, pub inline_puml_lib: bool, + pub conceptual_diagram: bool, } pub trait ViewGenerator { diff --git a/src/main.rs b/src/main.rs index abb42e4..796ffb9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,6 +58,13 @@ async fn main() { .action(ArgAction::Set) .default_value("plantuml"), ) + .arg( + Arg::new("conceptual") + .long("conceptual") + .help("Create conceptual ER diagram") + .action(ArgAction::SetTrue) + .default_value("false"), + ) .get_matches(); let mut s = lookup_parser( @@ -79,6 +86,7 @@ async fn main() { draw_enums: args.get_flag("enums"), draw_legend: args.get_flag("legend"), inline_puml_lib: args.get_flag("inline-puml-lib"), + conceptual_diagram: args.get_flag("conceptual"), }, ) .unwrap(); diff --git a/src/plantuml_generator.rs b/src/plantuml_generator.rs index 8134478..1e803e6 100644 --- a/src/plantuml_generator.rs +++ b/src/plantuml_generator.rs @@ -11,6 +11,7 @@ pub struct PlantUmlDefaultGenerator<'a> { static PUML_TEMPLATE: &str = "@startuml\n\n\ hide circle\n\ + hide empty members\n\ skinparam linetype ortho\n\n\ {puml_lib}\n\n\ {{ for ent in entities}}{ent}\n{{ endfor }}\n\ @@ -18,7 +19,8 @@ static PUML_TEMPLATE: &str = "@startuml\n\n\ {{ for fk in foreign_keys}}{fk}\n{{ endfor }}\n\ {{ for e in enums}}{e}\n{{ endfor }}{legend}\n@enduml"; -static ENTITY_TEMPLATE: &str = "table({name}) \\{\n{pks} ---\n{fks}{nns}{others}}\n"; +static ENTITY_TEMPLATE: &str = + "table({name}) \\{\n{pks} {{ if pks }} ---\n{{ endif }}{fks}{nns}{others}}\n"; static VIEW_TEMPLATE: &str = "view({name}{{ if materialized}}, $materialized=true{{ endif }}) \\{\n{columns}}\n"; @@ -154,7 +156,7 @@ impl<'a> PlantUmlDefaultGenerator<'a> { others, } } - fn entity_render(&self, tbl: &Table) -> Result { + fn entity_render(&self, tbl: &Table, conceptual: bool) -> Result { let sorted_columns = Self::sort_columns(&tbl.columns); let columns_render = |columns: Vec>| -> Result { @@ -178,19 +180,28 @@ impl<'a> PlantUmlDefaultGenerator<'a> { }, )?) }; + + let columns_render_if_not_conceptual = + |columns: Vec>| -> Result { + if !conceptual { + return columns_render(columns); + } + Ok(String::default()) + }; + Ok(self.str_templates.render( "ent", &SEntity { - pks: columns_render(sorted_columns.pks)?, - fks: columns_render(sorted_columns.fks)?, - nns: columns_render(sorted_columns.nns)?, - others: columns_render(sorted_columns.others)?, + pks: columns_render_if_not_conceptual(sorted_columns.pks)?, + fks: columns_render_if_not_conceptual(sorted_columns.fks)?, + nns: columns_render_if_not_conceptual(sorted_columns.nns)?, + others: columns_render_if_not_conceptual(sorted_columns.others)?, name: tbl.name.clone(), }, )?) } - fn view_render(&self, view: &View) -> Result { + fn view_render(&self, view: &View, conceptual: bool) -> Result { let columns_render = |columns: Vec>| -> Result { Ok::(columns.iter().try_fold( String::new(), @@ -212,10 +223,18 @@ impl<'a> PlantUmlDefaultGenerator<'a> { }, )?) }; + let columns_render_if_not_conceptual = + |columns: Vec>| -> Result { + if !conceptual { + return columns_render(columns); + } + Ok(String::default()) + }; + Ok(self.str_templates.render( "view", &SView { - columns: columns_render(view.columns.clone())?, + columns: columns_render_if_not_conceptual(view.columns.clone())?, name: view.name.clone(), materialized: view.materialized, }, @@ -232,12 +251,12 @@ impl ViewGenerator for PlantUmlDefaultGenerator<'_> { let entities: Vec = sql_erd .tables .iter() - .map(|tbl| self.entity_render(tbl)) + .map(|tbl| self.entity_render(tbl, opts.conceptual_diagram)) .collect::, crate::SqlantError>>()?; let views: Vec = sql_erd .views .iter() - .map(|view| self.view_render(view)) + .map(|view| self.view_render(view, opts.conceptual_diagram)) .collect::, crate::SqlantError>>()?; let foreign_keys: Vec = sql_erd