1pub fn snake_case(input: &str) -> String {
8 let mut out = String::with_capacity(input.len() + 4);
9 for (i, ch) in input.chars().enumerate() {
10 if ch.is_uppercase() {
11 if i != 0 {
12 out.push('_');
13 }
14 for lower in ch.to_lowercase() {
15 out.push(lower);
16 }
17 } else {
18 out.push(ch);
19 }
20 }
21 out
22}
23
24pub fn pluralize(word: &str) -> String {
26 if word.ends_with('y')
27 && !word.ends_with("ay")
28 && !word.ends_with("ey")
29 && !word.ends_with("oy")
30 && !word.ends_with("uy")
31 {
32 format!("{}ies", &word[..word.len() - 1])
33 } else if word.ends_with('s')
34 || word.ends_with("x")
35 || word.ends_with("ch")
36 || word.ends_with("sh")
37 {
38 format!("{word}es")
39 } else {
40 format!("{word}s")
41 }
42}
43
44pub fn table_name(model: &str) -> String {
46 pluralize(&snake_case(model))
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn snake_cases() {
55 assert_eq!(snake_case("User"), "user");
56 assert_eq!(snake_case("BlogPost"), "blog_post");
57 assert_eq!(snake_case("OAuthToken"), "o_auth_token");
58 }
59
60 #[test]
61 fn pluralizes() {
62 assert_eq!(pluralize("user"), "users");
63 assert_eq!(pluralize("category"), "categories");
64 assert_eq!(pluralize("box"), "boxes");
65 assert_eq!(pluralize("day"), "days");
66 }
67
68 #[test]
69 fn builds_table_names() {
70 assert_eq!(table_name("User"), "users");
71 assert_eq!(table_name("BlogPost"), "blog_posts");
72 assert_eq!(table_name("Category"), "categories");
73 }
74}