forge_core/schema/
field.rs1use serde::{Deserialize, Serialize};
2
3use super::types::{RustType, SqlType};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct FieldDef {
8 pub name: String,
10
11 pub column_name: String,
13
14 pub rust_type: RustType,
16
17 pub sql_type: SqlType,
19
20 pub nullable: bool,
22
23 pub doc: Option<String>,
25}
26
27impl FieldDef {
28 pub fn new(name: &str, rust_type: RustType) -> Self {
30 let sql_type = rust_type.to_sql_type();
31 let nullable = rust_type.is_nullable();
32 let column_name = to_snake_case(name);
33
34 Self {
35 name: name.to_string(),
36 column_name,
37 rust_type,
38 sql_type,
39 nullable,
40 doc: None,
41 }
42 }
43
44 pub fn to_typescript(&self) -> String {
45 let (ts_type, optional) = if self.nullable {
46 let inner_type = match &self.rust_type {
47 super::types::RustType::Option(inner) => inner.to_typescript(),
48 other => other.to_typescript(),
49 };
50 (inner_type, "?")
51 } else {
52 (self.rust_type.to_typescript(), "")
53 };
54 format!(" {}{}: {};", self.name, optional, ts_type)
55 }
56}
57
58fn to_snake_case(s: &str) -> String {
60 let mut result = String::new();
61 for (i, c) in s.chars().enumerate() {
62 if c.is_uppercase() {
63 if i > 0 {
64 result.push('_');
65 }
66 for lc in c.to_lowercase() {
68 result.push(lc);
69 }
70 } else {
71 result.push(c);
72 }
73 }
74 result
75}
76
77#[cfg(test)]
78#[allow(clippy::unwrap_used, clippy::indexing_slicing)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_field_def_basic() {
84 let field = FieldDef::new("email", RustType::String);
85 assert_eq!(field.name, "email");
86 assert_eq!(field.column_name, "email");
87 assert!(!field.nullable);
88 }
89
90 #[test]
91 fn test_field_def_nullable() {
92 let field = FieldDef::new("avatar_url", RustType::Option(Box::new(RustType::String)));
93 assert!(field.nullable);
94 }
95
96 #[test]
97 fn test_to_snake_case() {
98 assert_eq!(to_snake_case("createdAt"), "created_at");
99 assert_eq!(to_snake_case("userId"), "user_id");
100 assert_eq!(to_snake_case("HTTPServer"), "h_t_t_p_server");
101 }
102}