mod canonical;
mod conflict;
pub use canonical::{canonical, to_camel, to_pascal, to_snake};
pub use conflict::{detect_conflicts, ERR_NAME_CONFLICT, RESERVED_KEYS};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Style {
Snake,
Camel,
Pascal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Target {
Mysql,
Postgres,
Sqlite,
Mongodb,
Node,
Java,
Csharp,
Rust,
Go,
Python,
}
impl Target {
pub fn from_str_or_err(s: &str) -> Result<Target, String> {
match s.to_lowercase().as_str() {
"mysql" => Ok(Target::Mysql),
"postgres" | "pg" | "postgresql" => Ok(Target::Postgres),
"sqlite" => Ok(Target::Sqlite),
"mongo" | "mongodb" => Ok(Target::Mongodb),
"node" | "nodejs" => Ok(Target::Node),
"java" => Ok(Target::Java),
"csharp" | "cs" | "c#" => Ok(Target::Csharp),
"rust" => Ok(Target::Rust),
"go" | "golang" => Ok(Target::Go),
"python" | "py" => Ok(Target::Python),
other => Err(format!("未知命名目标: {other}")),
}
}
pub fn for_datasource_kind(kind: &str) -> Result<Target, String> {
Target::from_str_or_err(kind)
}
pub fn style(&self) -> Style {
match self {
Target::Mysql | Target::Postgres | Target::Sqlite | Target::Python => Style::Snake,
Target::Mongodb | Target::Node | Target::Java | Target::Csharp | Target::Rust => {
Style::Camel
}
Target::Go => Style::Pascal,
}
}
}
pub fn translate(logical: &str, target: Target) -> String {
let tokens = canonical(logical);
match target.style() {
Style::Snake => to_snake(&tokens),
Style::Camel => to_camel(&tokens),
Style::Pascal => to_pascal(&tokens),
}
}
pub fn translate_by_str(logical: &str, target: &str) -> Result<String, String> {
Ok(translate(logical, Target::from_str_or_err(target)?))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn target_style_table() {
assert_eq!(translate("orderTotal", Target::Mysql), "order_total");
assert_eq!(translate("orderTotal", Target::Postgres), "order_total");
assert_eq!(translate("orderTotal", Target::Sqlite), "order_total");
assert_eq!(translate("orderTotal", Target::Mongodb), "orderTotal");
assert_eq!(translate("orderTotal", Target::Node), "orderTotal");
assert_eq!(translate("orderTotal", Target::Java), "orderTotal");
assert_eq!(translate("orderTotal", Target::Csharp), "orderTotal");
assert_eq!(translate("orderTotal", Target::Rust), "orderTotal");
assert_eq!(translate("orderTotal", Target::Go), "OrderTotal"); assert_eq!(translate("orderTotal", Target::Python), "order_total");
}
#[test]
fn design_section_6_2_pipeline() {
for src in ["orderTotal", "order_total", "Order.Total"] {
assert_eq!(translate(src, Target::Mysql), "order_total");
assert_eq!(translate(src, Target::Mongodb), "orderTotal");
assert_eq!(translate(src, Target::Go), "OrderTotal");
assert_eq!(translate(src, Target::Python), "order_total");
}
}
#[test]
fn unknown_target_errors() {
assert!(Target::from_str_or_err("oracle").is_err());
assert!(translate_by_str("orderTotal", "oracle").is_err());
}
}