Skip to content

Commit 783c551

Browse files
committed
Add diagram direction support (#58)
1 parent 6e197ce commit 783c551

File tree

5 files changed

+81
-12
lines changed

5 files changed

+81
-12
lines changed

src/cli.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,12 @@ pub fn parse() -> ArgMatches {
5757
.action(ArgAction::SetTrue)
5858
.default_value("false"),
5959
)
60+
.arg(
61+
Arg::new("direction")
62+
.long("direction")
63+
.value_parser(["tb", "bt", "lr", "rl"])
64+
.help("Optionally set the direction of the generated diagram")
65+
.action(ArgAction::Set),
66+
)
6067
.get_matches()
6168
}

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct GeneratorConfigOptions {
1919
pub draw_legend: bool,
2020
pub inline_puml_lib: bool,
2121
pub conceptual_diagram: bool,
22+
pub direction: Option<Direction>,
2223
}
2324

2425
pub trait ViewGenerator {
@@ -54,3 +55,12 @@ pub fn get_generator(generator_type: GeneratorType) -> Result<Box<dyn ViewGenera
5455
GeneratorType::Mermaid => Ok(Box::new(MermaidGenerator::new()?)),
5556
}
5657
}
58+
59+
#[derive(Clone, Debug, Display, EnumString, Eq, PartialEq, PartialOrd, Ord)]
60+
#[strum(serialize_all = "lowercase")]
61+
pub enum Direction {
62+
TB,
63+
BT,
64+
LR,
65+
RL,
66+
}

src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::str::FromStr;
22

33
use clap::ArgMatches;
4-
use sqlant::{get_generator, lookup_parser, GeneratorConfigOptions, GeneratorType};
4+
use sqlant::{get_generator, lookup_parser, Direction, GeneratorConfigOptions, GeneratorType};
55

66
fn get_arg(args: &ArgMatches, arg_name: &str) -> String {
77
args.get_one::<String>(arg_name).unwrap().to_string()
@@ -22,6 +22,10 @@ async fn main() {
2222
let generator_type =
2323
GeneratorType::from_str(&output_arg).expect("Generator type {output_arg} isn't supported");
2424
let rndr = get_generator(generator_type).unwrap();
25+
let direction_arg = args.get_one::<String>("direction");
26+
let direction = direction_arg.map(|dir| {
27+
Direction::from_str(dir).unwrap_or_else(|_| panic!("Direction {dir} isn't supported"))
28+
});
2529
let result = rndr
2630
.generate(
2731
erd,
@@ -31,6 +35,7 @@ async fn main() {
3135
draw_legend: args.get_flag("legend"),
3236
inline_puml_lib: args.get_flag("inline-puml-lib"),
3337
conceptual_diagram: args.get_flag("conceptual"),
38+
direction,
3439
},
3540
)
3641
.unwrap();

src/mermaid_generator.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
use std::sync::Arc;
22

33
use super::sql_entities::{SqlERData, Table, TableColumn};
4-
use crate::{GeneratorConfigOptions, ViewGenerator};
4+
use crate::{Direction, GeneratorConfigOptions, ViewGenerator};
55
use serde::Serialize;
6-
use tinytemplate::{format_unescaped, TinyTemplate};
6+
use tinytemplate::{TinyTemplate, format_unescaped};
77

8-
static MERMAID_TEMPLATE: &str = r#"erDiagram
8+
static MERMAID_TEMPLATE: &str = r#"erDiagram{{ if direction }}
9+
direction {direction}{{ endif }}
910
{{ for ent in entities}}{ent}{{ endfor }}
1011
{{ for en in enums}}{en}{{ endfor }}
1112
{{ for fk in foreign_keys}}{fk}{{ endfor }}
1213
"#;
1314

1415
static ENTITY_TEMPLATE: &str = "{name} \\{\n{pks}{fks}{others}}\n";
1516

16-
static COLUMN_TEMPLATE: &str =
17-
" {col.datatype} {col.name}{{ if is_pk_or_fk }} {{ endif }}{{ if is_pk }}PK,{{ endif }}{{ if is_fk }}FK{{ endif }}";
17+
static COLUMN_TEMPLATE: &str = " {col.datatype} {col.name}{{ if is_pk_or_fk }} {{ endif }}{{ if is_pk }}PK,{{ endif }}{{ if is_fk }}FK{{ endif }}";
1818

19-
static REL_TEMPLATE: &str =
20-
"{source_table_name} {{ if is_zero_one_to_one }}|o--||{{else}}}o--||{{ endif }} {target_table_name}: \"\"\n";
19+
static REL_TEMPLATE: &str = "{source_table_name} {{ if is_zero_one_to_one }}|o--||{{else}}}o--||{{ endif }} {target_table_name}: \"\"\n";
2120

2221
const ENUM_TEMPLATE: &str = "\"{name} (ENUM)\" \\{\n{{ for v in values}} {v} _\n{{ endfor }}}";
2322

@@ -38,8 +37,28 @@ struct SColumn<'a> {
3837
is_nn: bool,
3938
}
4039

40+
#[derive(Serialize)]
41+
enum SDirection {
42+
TB,
43+
BT,
44+
LR,
45+
RL,
46+
}
47+
48+
impl From<&Direction> for SDirection {
49+
fn from(value: &Direction) -> Self {
50+
match value {
51+
Direction::TB => Self::TB,
52+
Direction::BT => Self::BT,
53+
Direction::LR => Self::LR,
54+
Direction::RL => Self::RL,
55+
}
56+
}
57+
}
58+
4159
#[derive(Serialize)]
4260
struct SMermaid {
61+
direction: Option<SDirection>,
4362
entities: Vec<String>,
4463
enums: Vec<String>,
4564
foreign_keys: Vec<String>,
@@ -184,6 +203,7 @@ impl ViewGenerator for MermaidGenerator<'_> {
184203
Ok(self.str_templates.render(
185204
"mermaid",
186205
&SMermaid {
206+
direction: opts.direction.as_ref().map(Into::into),
187207
entities,
188208
enums,
189209
foreign_keys,

src/plantuml_generator.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use std::sync::Arc;
22

33
use super::sql_entities::{SqlERData, Table, TableColumn};
4-
use crate::{sql_entities::View, GeneratorConfigOptions, ViewGenerator};
4+
use crate::{Direction, GeneratorConfigOptions, ViewGenerator, sql_entities::View};
55
use serde::Serialize;
6-
use tinytemplate::{format_unescaped, TinyTemplate};
6+
use tinytemplate::{TinyTemplate, format_unescaped};
77

88
pub struct PlantUmlDefaultGenerator<'a> {
99
str_templates: TinyTemplate<'a>,
1010
}
1111

1212
static PUML_TEMPLATE: &str = "@startuml\n\n\
13+
{{ if direction }}{ direction }\n{{ endif }}\
1314
hide circle\n\
1415
hide empty members\n\
1516
skinparam linetype ortho\n\n\
@@ -27,8 +28,7 @@ static VIEW_TEMPLATE: &str =
2728

2829
static COLUMN_TEMPLATE: &str = " column({col.name}, \"{col.datatype}\"{{ if is_pk }}, $pk=true{{ endif }}{{ if is_fk }}, $fk=true{{ endif }}{{if is_nn}}, $nn=true{{ endif }})\n";
2930

30-
static REL_TEMPLATE: &str =
31-
"{source_table_name} {{ if is_zero_one_to_one }}|o--||{{else}}}o--||{{ endif }} {target_table_name}\n";
31+
static REL_TEMPLATE: &str = "{source_table_name} {{ if is_zero_one_to_one }}|o--||{{else}}}o--||{{ endif }} {target_table_name}\n";
3232

3333
static ENUM_TEMPLATE: &str =
3434
"enum({name}, \"{{ for v in values}}{{if @last}}{v}{{else}}{v}, {{ endif }}{{ endfor }}\")\n";
@@ -69,6 +69,25 @@ struct SEntity {
6969
#[derive(Serialize)]
7070
struct SLegend(String);
7171

72+
#[derive(Serialize)]
73+
struct SDirection(String);
74+
75+
impl TryFrom<&Direction> for SDirection {
76+
type Error = crate::SqlantError;
77+
fn try_from(value: &Direction) -> Result<Self, crate::SqlantError> {
78+
match value {
79+
Direction::TB => Ok(Self("top to bottom direction".into())),
80+
Direction::BT => Err(crate::SqlantError::Generator(
81+
"bt (bottom-to-top) direction is not available in plantuml.".into(),
82+
)),
83+
Direction::LR => Ok(Self("left to right direction".into())),
84+
Direction::RL => Err(crate::SqlantError::Generator(
85+
"rl (right-to-left) direction is not available in plantuml.".into(),
86+
)),
87+
}
88+
}
89+
}
90+
7291
#[derive(Serialize)]
7392
struct SPuml {
7493
puml_lib: String,
@@ -78,6 +97,7 @@ struct SPuml {
7897
foreign_keys: Vec<String>,
7998
enums: Vec<String>,
8099
legend: Option<SLegend>,
100+
direction: Option<SDirection>,
81101
}
82102

83103
#[derive(Serialize)]
@@ -304,6 +324,12 @@ impl ViewGenerator for PlantUmlDefaultGenerator<'_> {
304324
PUML_LIB_INCLUDE.into()
305325
};
306326

327+
let direction = if let Some(direction) = &opts.direction {
328+
Some(SDirection::try_from(direction)?)
329+
} else {
330+
None
331+
};
332+
307333
Ok(self.str_templates.render(
308334
"puml",
309335
&SPuml {
@@ -313,6 +339,7 @@ impl ViewGenerator for PlantUmlDefaultGenerator<'_> {
313339
enums,
314340
legend,
315341
views,
342+
direction,
316343
},
317344
)?)
318345
}

0 commit comments

Comments
 (0)