Skip to main content

sql_splitter/graph/format/
mod.rs

1//! Output format implementations for ERD visualization.
2
3mod dot;
4mod html;
5pub(crate) mod json;
6mod mermaid;
7
8pub use dot::to_dot;
9pub use html::to_html;
10pub use json::to_json;
11#[allow(unused_imports)]
12pub use json::{ColumnJson, ErdJson, ErdStats, RelationshipJson, TableJson};
13pub use mermaid::to_mermaid;
14
15use std::fmt;
16use std::str::FromStr;
17
18/// Output format for ERD export
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
20pub enum OutputFormat {
21    /// Graphviz DOT format (ERD style)
22    #[default]
23    Dot,
24    /// Mermaid erDiagram format
25    Mermaid,
26    /// JSON format for programmatic use
27    Json,
28    /// Interactive HTML with toggleable dark mode
29    Html,
30}
31
32impl FromStr for OutputFormat {
33    type Err = String;
34
35    fn from_str(s: &str) -> Result<Self, Self::Err> {
36        match s.to_lowercase().as_str() {
37            "dot" | "graphviz" => Ok(OutputFormat::Dot),
38            "mermaid" | "mmd" => Ok(OutputFormat::Mermaid),
39            "json" => Ok(OutputFormat::Json),
40            "html" => Ok(OutputFormat::Html),
41            _ => Err(format!(
42                "Unknown format: {}. Valid options: dot, mermaid, json, html",
43                s
44            )),
45        }
46    }
47}
48
49impl fmt::Display for OutputFormat {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match self {
52            OutputFormat::Dot => write!(f, "dot"),
53            OutputFormat::Mermaid => write!(f, "mermaid"),
54            OutputFormat::Json => write!(f, "json"),
55            OutputFormat::Html => write!(f, "html"),
56        }
57    }
58}
59
60impl OutputFormat {
61    /// Get file extension for this format
62    pub fn extension(&self) -> &'static str {
63        match self {
64            OutputFormat::Dot => "dot",
65            OutputFormat::Mermaid => "mmd",
66            OutputFormat::Json => "json",
67            OutputFormat::Html => "html",
68        }
69    }
70
71    /// Detect format from file extension
72    pub fn from_extension(ext: &str) -> Option<Self> {
73        match ext.to_lowercase().as_str() {
74            "dot" | "gv" => Some(OutputFormat::Dot),
75            "mmd" | "mermaid" => Some(OutputFormat::Mermaid),
76            "json" => Some(OutputFormat::Json),
77            "html" | "htm" => Some(OutputFormat::Html),
78            "png" | "svg" | "pdf" => Some(OutputFormat::Dot), // Will be rendered
79            _ => None,
80        }
81    }
82}
83
84/// Layout direction for diagram
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
86pub enum Layout {
87    /// Left to right
88    #[default]
89    LR,
90    /// Top to bottom
91    TB,
92}
93
94impl FromStr for Layout {
95    type Err = String;
96
97    fn from_str(s: &str) -> Result<Self, Self::Err> {
98        match s.to_lowercase().as_str() {
99            "lr" | "left-right" | "horizontal" => Ok(Layout::LR),
100            "tb" | "td" | "top-bottom" | "top-down" | "vertical" => Ok(Layout::TB),
101            _ => Err(format!("Unknown layout: {}. Valid options: lr, tb", s)),
102        }
103    }
104}
105
106impl fmt::Display for Layout {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        match self {
109            Layout::LR => write!(f, "lr"),
110            Layout::TB => write!(f, "tb"),
111        }
112    }
113}