Skip to main content

ruest_db_codegen/
naming.rs

1use ruest_db_schema::{Field, FieldKind, Model, ScalarType};
2
3pub fn table_name(model: &str) -> String {
4    let snake = to_snake(model);
5    pluralize(&snake)
6}
7
8pub fn column_name(field: &str) -> String {
9    to_snake(field)
10}
11
12pub fn rust_module(model: &str) -> String {
13    to_snake(model)
14}
15
16pub fn rust_struct(model: &str) -> String {
17    model.to_string()
18}
19
20pub fn create_input_name(model: &str) -> String {
21    format!("Create{model}")
22}
23
24pub fn update_input_name(model: &str) -> String {
25    format!("Update{model}")
26}
27
28pub fn delegate_name(model: &str) -> String {
29    format!("{model}Delegate")
30}
31
32pub fn pg_type(field: &Field) -> String {
33    match &field.kind {
34        FieldKind::Scalar(t) => match t {
35            ScalarType::String => "TEXT".into(),
36            ScalarType::Int => "INTEGER".into(),
37            ScalarType::Float => "DOUBLE PRECISION".into(),
38            ScalarType::Boolean => "BOOLEAN".into(),
39            ScalarType::DateTime => "TIMESTAMPTZ".into(),
40            ScalarType::Uuid => "UUID".into(),
41        },
42        FieldKind::Model(_) => "TEXT".into(),
43    }
44}
45
46pub fn default_sql(field: &Field) -> Option<String> {
47    use ruest_db_schema::{Attribute, DefaultValue};
48
49    for attr in &field.attributes {
50        if let Attribute::Default(d) = attr {
51            return Some(match d {
52                DefaultValue::Uuid => "gen_random_uuid()".into(),
53                DefaultValue::Now => "NOW()".into(),
54                DefaultValue::Literal(v) => format!("'{v}'"),
55            });
56        }
57    }
58    None
59}
60
61pub fn is_db_column(field: &Field) -> bool {
62    matches!(field.kind, FieldKind::Scalar(_))
63}
64
65fn to_snake(s: &str) -> String {
66    let mut out = String::new();
67    for (i, ch) in s.chars().enumerate() {
68        if ch.is_ascii_uppercase() {
69            if i > 0 {
70                out.push('_');
71            }
72            out.push(ch.to_ascii_lowercase());
73        } else {
74            out.push(ch);
75        }
76    }
77    out
78}
79
80fn pluralize(s: &str) -> String {
81    if s.ends_with('y') && s.len() > 1 && !"aeiou".contains(s.as_bytes()[s.len() - 2] as char) {
82        format!("{}ies", &s[..s.len() - 1])
83    } else if s.ends_with('s') || s.ends_with('x') || s.ends_with("ch") || s.ends_with("sh") {
84        format!("{s}es")
85    } else {
86        format!("{s}s")
87    }
88}
89
90pub fn table_columns(model: &Model) -> Vec<&Field> {
91    model.fields.iter().filter(|f| is_db_column(f)).collect()
92}