ruest_db_codegen/
naming.rs1use 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}