1use heck::ToUpperCamelCase;
2
3use super::RustType;
4
5pub fn map_type(data_type: &str, column_type: &str) -> RustType {
6 let dt = data_type.to_lowercase();
7 let ct = column_type.to_lowercase();
8 let is_unsigned = ct.contains("unsigned");
9
10 if ct.starts_with("enum(") {
12 return RustType::simple("String");
16 }
17
18 match dt.as_str() {
19 "tinyint" => {
20 if ct == "tinyint(1)" {
21 RustType::simple("bool")
22 } else if is_unsigned {
23 RustType::simple("u8")
24 } else {
25 RustType::simple("i8")
26 }
27 }
28 "smallint" => {
29 if is_unsigned {
30 RustType::simple("u16")
31 } else {
32 RustType::simple("i16")
33 }
34 }
35 "mediumint" | "int" => {
36 if is_unsigned {
37 RustType::simple("u32")
38 } else {
39 RustType::simple("i32")
40 }
41 }
42 "bigint" => {
43 if is_unsigned {
44 RustType::simple("u64")
45 } else {
46 RustType::simple("i64")
47 }
48 }
49 "float" => RustType::simple("f32"),
50 "double" => RustType::simple("f64"),
51 "decimal" | "numeric" => {
52 RustType::with_import("Decimal", "use rust_decimal::Decimal;")
53 }
54 "varchar" | "char" | "text" | "tinytext" | "mediumtext" | "longtext" | "enum" | "set" => {
55 RustType::simple("String")
56 }
57 "binary" | "varbinary" | "blob" | "tinyblob" | "mediumblob" | "longblob" => {
58 RustType::simple("Vec<u8>")
59 }
60 "date" => RustType::with_import("NaiveDate", "use chrono::NaiveDate;"),
61 "time" => RustType::with_import("NaiveTime", "use chrono::NaiveTime;"),
62 "datetime" => {
63 RustType::with_import("NaiveDateTime", "use chrono::NaiveDateTime;")
64 }
65 "timestamp" => {
66 RustType::with_import("DateTime<Utc>", "use chrono::{DateTime, Utc};")
67 }
68 "json" => RustType::with_import("Value", "use serde_json::Value;"),
69 "year" => RustType::simple("i16"),
70 "bit" => RustType::simple("Vec<u8>"),
71 _ => RustType::simple("String"),
72 }
73}
74
75pub fn resolve_enum_type(table_name: &str, column_name: &str) -> String {
77 let enum_name = format!("{}_{}", table_name, column_name);
78 enum_name.to_upper_camel_case()
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
88 fn test_tinyint1_is_bool() {
89 assert_eq!(map_type("tinyint", "tinyint(1)").path, "bool");
90 }
91
92 #[test]
93 fn test_tinyint_signed() {
94 assert_eq!(map_type("tinyint", "tinyint").path, "i8");
95 }
96
97 #[test]
98 fn test_tinyint_unsigned() {
99 assert_eq!(map_type("tinyint", "tinyint unsigned").path, "u8");
100 }
101
102 #[test]
103 fn test_tinyint3_signed() {
104 assert_eq!(map_type("tinyint", "tinyint(3)").path, "i8");
105 }
106
107 #[test]
108 fn test_tinyint3_unsigned() {
109 assert_eq!(map_type("tinyint", "tinyint(3) unsigned").path, "u8");
110 }
111
112 #[test]
115 fn test_smallint_signed() {
116 assert_eq!(map_type("smallint", "smallint").path, "i16");
117 }
118
119 #[test]
120 fn test_smallint_unsigned() {
121 assert_eq!(map_type("smallint", "smallint unsigned").path, "u16");
122 }
123
124 #[test]
127 fn test_int_signed() {
128 assert_eq!(map_type("int", "int").path, "i32");
129 }
130
131 #[test]
132 fn test_int_unsigned() {
133 assert_eq!(map_type("int", "int unsigned").path, "u32");
134 }
135
136 #[test]
137 fn test_mediumint_signed() {
138 assert_eq!(map_type("mediumint", "mediumint").path, "i32");
139 }
140
141 #[test]
142 fn test_mediumint_unsigned() {
143 assert_eq!(map_type("mediumint", "mediumint unsigned").path, "u32");
144 }
145
146 #[test]
147 fn test_int11_signed() {
148 assert_eq!(map_type("int", "int(11)").path, "i32");
149 }
150
151 #[test]
152 fn test_int11_unsigned() {
153 assert_eq!(map_type("int", "int(11) unsigned").path, "u32");
154 }
155
156 #[test]
159 fn test_bigint_signed() {
160 assert_eq!(map_type("bigint", "bigint").path, "i64");
161 }
162
163 #[test]
164 fn test_bigint_unsigned() {
165 assert_eq!(map_type("bigint", "bigint unsigned").path, "u64");
166 }
167
168 #[test]
169 fn test_bigint20_signed() {
170 assert_eq!(map_type("bigint", "bigint(20)").path, "i64");
171 }
172
173 #[test]
176 fn test_float() {
177 assert_eq!(map_type("float", "float").path, "f32");
178 }
179
180 #[test]
181 fn test_double() {
182 assert_eq!(map_type("double", "double").path, "f64");
183 }
184
185 #[test]
188 fn test_decimal() {
189 let rt = map_type("decimal", "decimal(10,2)");
190 assert_eq!(rt.path, "Decimal");
191 assert!(rt.needs_import.as_ref().unwrap().contains("rust_decimal"));
192 }
193
194 #[test]
195 fn test_numeric() {
196 let rt = map_type("numeric", "numeric");
197 assert_eq!(rt.path, "Decimal");
198 assert!(rt.needs_import.is_some());
199 }
200
201 #[test]
204 fn test_varchar() {
205 assert_eq!(map_type("varchar", "varchar(255)").path, "String");
206 }
207
208 #[test]
209 fn test_char() {
210 assert_eq!(map_type("char", "char(1)").path, "String");
211 }
212
213 #[test]
214 fn test_text() {
215 assert_eq!(map_type("text", "text").path, "String");
216 }
217
218 #[test]
219 fn test_tinytext() {
220 assert_eq!(map_type("tinytext", "tinytext").path, "String");
221 }
222
223 #[test]
224 fn test_mediumtext() {
225 assert_eq!(map_type("mediumtext", "mediumtext").path, "String");
226 }
227
228 #[test]
229 fn test_longtext() {
230 assert_eq!(map_type("longtext", "longtext").path, "String");
231 }
232
233 #[test]
234 fn test_set() {
235 assert_eq!(map_type("set", "set('a','b')").path, "String");
236 }
237
238 #[test]
241 fn test_binary() {
242 assert_eq!(map_type("binary", "binary(16)").path, "Vec<u8>");
243 }
244
245 #[test]
246 fn test_varbinary() {
247 assert_eq!(map_type("varbinary", "varbinary(255)").path, "Vec<u8>");
248 }
249
250 #[test]
251 fn test_blob() {
252 assert_eq!(map_type("blob", "blob").path, "Vec<u8>");
253 }
254
255 #[test]
256 fn test_tinyblob() {
257 assert_eq!(map_type("tinyblob", "tinyblob").path, "Vec<u8>");
258 }
259
260 #[test]
263 fn test_date() {
264 let rt = map_type("date", "date");
265 assert_eq!(rt.path, "NaiveDate");
266 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
267 }
268
269 #[test]
270 fn test_time() {
271 let rt = map_type("time", "time");
272 assert_eq!(rt.path, "NaiveTime");
273 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
274 }
275
276 #[test]
277 fn test_datetime() {
278 let rt = map_type("datetime", "datetime");
279 assert_eq!(rt.path, "NaiveDateTime");
280 assert!(rt.needs_import.is_some());
281 }
282
283 #[test]
284 fn test_timestamp() {
285 let rt = map_type("timestamp", "timestamp");
286 assert_eq!(rt.path, "DateTime<Utc>");
287 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
288 }
289
290 #[test]
293 fn test_json() {
294 let rt = map_type("json", "json");
295 assert_eq!(rt.path, "Value");
296 assert!(rt.needs_import.as_ref().unwrap().contains("serde_json"));
297 }
298
299 #[test]
300 fn test_year() {
301 assert_eq!(map_type("year", "year").path, "i16");
302 }
303
304 #[test]
305 fn test_bit() {
306 assert_eq!(map_type("bit", "bit(1)").path, "Vec<u8>");
307 }
308
309 #[test]
312 fn test_enum_placeholder() {
313 assert_eq!(map_type("enum", "enum('a','b','c')").path, "String");
314 }
315
316 #[test]
319 fn test_case_insensitive_int() {
320 assert_eq!(map_type("INT", "INT").path, "i32");
321 }
322
323 #[test]
324 fn test_case_insensitive_tinyint1() {
325 assert_eq!(map_type("TINYINT", "TINYINT(1)").path, "bool");
326 }
327
328 #[test]
331 fn test_geometry_fallback() {
332 assert_eq!(map_type("geometry", "geometry").path, "String");
333 }
334
335 #[test]
336 fn test_point_fallback() {
337 assert_eq!(map_type("point", "point").path, "String");
338 }
339
340 #[test]
343 fn test_resolve_enum_users_status() {
344 assert_eq!(resolve_enum_type("users", "status"), "UsersStatus");
345 }
346
347 #[test]
348 fn test_resolve_enum_user_roles_role_type() {
349 assert_eq!(resolve_enum_type("user_roles", "role_type"), "UserRolesRoleType");
350 }
351
352 #[test]
353 fn test_resolve_enum_short_names() {
354 assert_eq!(resolve_enum_type("t", "c"), "TC");
355 }
356
357 #[test]
358 fn test_resolve_enum_order_items_size() {
359 assert_eq!(resolve_enum_type("order_items", "size"), "OrderItemsSize");
360 }
361}