1use heck::ToUpperCamelCase;
2
3use super::RustType;
4use crate::cli::TimeCrate;
5
6pub fn map_type(data_type: &str, column_type: &str, time_crate: TimeCrate) -> RustType {
7 let dt = data_type.to_lowercase();
8 let ct = column_type.to_lowercase();
9 let is_unsigned = ct.contains("unsigned");
10
11 if ct.starts_with("enum(") {
13 return RustType::simple("String");
17 }
18
19 match dt.as_str() {
20 "tinyint" => {
21 if ct == "tinyint(1)" {
22 RustType::simple("bool")
23 } else if is_unsigned {
24 RustType::simple("u8")
25 } else {
26 RustType::simple("i8")
27 }
28 }
29 "smallint" => {
30 if is_unsigned {
31 RustType::simple("u16")
32 } else {
33 RustType::simple("i16")
34 }
35 }
36 "mediumint" | "int" => {
37 if is_unsigned {
38 RustType::simple("u32")
39 } else {
40 RustType::simple("i32")
41 }
42 }
43 "bigint" => {
44 if is_unsigned {
45 RustType::simple("u64")
46 } else {
47 RustType::simple("i64")
48 }
49 }
50 "float" => RustType::simple("f32"),
51 "double" => RustType::simple("f64"),
52 "decimal" | "numeric" => RustType::with_import("Decimal", "use rust_decimal::Decimal;"),
53 "varchar" | "char" | "text" | "tinytext" | "mediumtext" | "longtext" | "enum" | "set" => {
54 RustType::simple("String")
55 }
56 "binary" | "varbinary" | "blob" | "tinyblob" | "mediumblob" | "longblob" => {
57 RustType::simple("Vec<u8>")
58 }
59 "date" => match time_crate {
60 TimeCrate::Chrono => RustType::with_import("NaiveDate", "use chrono::NaiveDate;"),
61 TimeCrate::Time => RustType::with_import("Date", "use time::Date;"),
62 },
63 "time" => match time_crate {
64 TimeCrate::Chrono => RustType::with_import("NaiveTime", "use chrono::NaiveTime;"),
65 TimeCrate::Time => RustType::with_import("Time", "use time::Time;"),
66 },
67 "datetime" => match time_crate {
68 TimeCrate::Chrono => {
69 RustType::with_import("NaiveDateTime", "use chrono::NaiveDateTime;")
70 }
71 TimeCrate::Time => {
72 RustType::with_import("PrimitiveDateTime", "use time::PrimitiveDateTime;")
73 }
74 },
75 "timestamp" => match time_crate {
76 TimeCrate::Chrono => {
77 RustType::with_import("DateTime<Utc>", "use chrono::{DateTime, Utc};")
78 }
79 TimeCrate::Time => RustType::with_import("OffsetDateTime", "use time::OffsetDateTime;"),
80 },
81 "json" => RustType::with_import("Value", "use serde_json::Value;"),
82 "year" => RustType::simple("i16"),
83 "bit" => {
84 if ct == "bit(1)" {
86 RustType::simple("bool")
87 } else {
88 RustType::simple("Vec<u8>")
89 }
90 }
91 "boolean" | "bool" => RustType::simple("bool"),
92 _ => RustType::simple("String"),
93 }
94}
95
96pub fn resolve_enum_type(table_name: &str, column_name: &str) -> String {
98 let enum_name = format!("{}_{}", table_name, column_name);
99 enum_name.to_upper_camel_case()
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::cli::TimeCrate;
106
107 #[test]
110 fn test_tinyint1_is_bool() {
111 assert_eq!(
112 map_type("tinyint", "tinyint(1)", TimeCrate::Chrono).path,
113 "bool"
114 );
115 }
116
117 #[test]
118 fn test_tinyint_signed() {
119 assert_eq!(map_type("tinyint", "tinyint", TimeCrate::Chrono).path, "i8");
120 }
121
122 #[test]
123 fn test_tinyint_unsigned() {
124 assert_eq!(
125 map_type("tinyint", "tinyint unsigned", TimeCrate::Chrono).path,
126 "u8"
127 );
128 }
129
130 #[test]
131 fn test_tinyint3_signed() {
132 assert_eq!(
133 map_type("tinyint", "tinyint(3)", TimeCrate::Chrono).path,
134 "i8"
135 );
136 }
137
138 #[test]
139 fn test_tinyint3_unsigned() {
140 assert_eq!(
141 map_type("tinyint", "tinyint(3) unsigned", TimeCrate::Chrono).path,
142 "u8"
143 );
144 }
145
146 #[test]
149 fn test_smallint_signed() {
150 assert_eq!(
151 map_type("smallint", "smallint", TimeCrate::Chrono).path,
152 "i16"
153 );
154 }
155
156 #[test]
157 fn test_smallint_unsigned() {
158 assert_eq!(
159 map_type("smallint", "smallint unsigned", TimeCrate::Chrono).path,
160 "u16"
161 );
162 }
163
164 #[test]
167 fn test_int_signed() {
168 assert_eq!(map_type("int", "int", TimeCrate::Chrono).path, "i32");
169 }
170
171 #[test]
172 fn test_int_unsigned() {
173 assert_eq!(
174 map_type("int", "int unsigned", TimeCrate::Chrono).path,
175 "u32"
176 );
177 }
178
179 #[test]
180 fn test_mediumint_signed() {
181 assert_eq!(
182 map_type("mediumint", "mediumint", TimeCrate::Chrono).path,
183 "i32"
184 );
185 }
186
187 #[test]
188 fn test_mediumint_unsigned() {
189 assert_eq!(
190 map_type("mediumint", "mediumint unsigned", TimeCrate::Chrono).path,
191 "u32"
192 );
193 }
194
195 #[test]
196 fn test_int11_signed() {
197 assert_eq!(map_type("int", "int(11)", TimeCrate::Chrono).path, "i32");
198 }
199
200 #[test]
201 fn test_int11_unsigned() {
202 assert_eq!(
203 map_type("int", "int(11) unsigned", TimeCrate::Chrono).path,
204 "u32"
205 );
206 }
207
208 #[test]
211 fn test_bigint_signed() {
212 assert_eq!(map_type("bigint", "bigint", TimeCrate::Chrono).path, "i64");
213 }
214
215 #[test]
216 fn test_bigint_unsigned() {
217 assert_eq!(
218 map_type("bigint", "bigint unsigned", TimeCrate::Chrono).path,
219 "u64"
220 );
221 }
222
223 #[test]
224 fn test_bigint20_signed() {
225 assert_eq!(
226 map_type("bigint", "bigint(20)", TimeCrate::Chrono).path,
227 "i64"
228 );
229 }
230
231 #[test]
234 fn test_float() {
235 assert_eq!(map_type("float", "float", TimeCrate::Chrono).path, "f32");
236 }
237
238 #[test]
239 fn test_double() {
240 assert_eq!(map_type("double", "double", TimeCrate::Chrono).path, "f64");
241 }
242
243 #[test]
246 fn test_decimal() {
247 let rt = map_type("decimal", "decimal(10,2)", TimeCrate::Chrono);
248 assert_eq!(rt.path, "Decimal");
249 assert!(rt.needs_import.as_ref().unwrap().contains("rust_decimal"));
250 }
251
252 #[test]
253 fn test_numeric() {
254 let rt = map_type("numeric", "numeric", TimeCrate::Chrono);
255 assert_eq!(rt.path, "Decimal");
256 assert!(rt.needs_import.is_some());
257 }
258
259 #[test]
262 fn test_varchar() {
263 assert_eq!(
264 map_type("varchar", "varchar(255)", TimeCrate::Chrono).path,
265 "String"
266 );
267 }
268
269 #[test]
270 fn test_char() {
271 assert_eq!(
272 map_type("char", "char(1)", TimeCrate::Chrono).path,
273 "String"
274 );
275 }
276
277 #[test]
278 fn test_text() {
279 assert_eq!(map_type("text", "text", TimeCrate::Chrono).path, "String");
280 }
281
282 #[test]
283 fn test_tinytext() {
284 assert_eq!(
285 map_type("tinytext", "tinytext", TimeCrate::Chrono).path,
286 "String"
287 );
288 }
289
290 #[test]
291 fn test_mediumtext() {
292 assert_eq!(
293 map_type("mediumtext", "mediumtext", TimeCrate::Chrono).path,
294 "String"
295 );
296 }
297
298 #[test]
299 fn test_longtext() {
300 assert_eq!(
301 map_type("longtext", "longtext", TimeCrate::Chrono).path,
302 "String"
303 );
304 }
305
306 #[test]
307 fn test_set() {
308 assert_eq!(
309 map_type("set", "set('a','b')", TimeCrate::Chrono).path,
310 "String"
311 );
312 }
313
314 #[test]
317 fn test_binary() {
318 assert_eq!(
319 map_type("binary", "binary(16)", TimeCrate::Chrono).path,
320 "Vec<u8>"
321 );
322 }
323
324 #[test]
325 fn test_varbinary() {
326 assert_eq!(
327 map_type("varbinary", "varbinary(255)", TimeCrate::Chrono).path,
328 "Vec<u8>"
329 );
330 }
331
332 #[test]
333 fn test_blob() {
334 assert_eq!(map_type("blob", "blob", TimeCrate::Chrono).path, "Vec<u8>");
335 }
336
337 #[test]
338 fn test_tinyblob() {
339 assert_eq!(
340 map_type("tinyblob", "tinyblob", TimeCrate::Chrono).path,
341 "Vec<u8>"
342 );
343 }
344
345 #[test]
348 fn test_date() {
349 let rt = map_type("date", "date", TimeCrate::Chrono);
350 assert_eq!(rt.path, "NaiveDate");
351 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
352 }
353
354 #[test]
355 fn test_time() {
356 let rt = map_type("time", "time", TimeCrate::Chrono);
357 assert_eq!(rt.path, "NaiveTime");
358 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
359 }
360
361 #[test]
362 fn test_datetime() {
363 let rt = map_type("datetime", "datetime", TimeCrate::Chrono);
364 assert_eq!(rt.path, "NaiveDateTime");
365 assert!(rt.needs_import.is_some());
366 }
367
368 #[test]
369 fn test_timestamp() {
370 let rt = map_type("timestamp", "timestamp", TimeCrate::Chrono);
371 assert_eq!(rt.path, "DateTime<Utc>");
372 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
373 }
374
375 #[test]
378 fn test_json() {
379 let rt = map_type("json", "json", TimeCrate::Chrono);
380 assert_eq!(rt.path, "Value");
381 assert!(rt.needs_import.as_ref().unwrap().contains("serde_json"));
382 }
383
384 #[test]
385 fn test_year() {
386 assert_eq!(map_type("year", "year", TimeCrate::Chrono).path, "i16");
387 }
388
389 #[test]
390 fn test_bit1_is_bool() {
391 assert_eq!(map_type("bit", "bit(1)", TimeCrate::Chrono).path, "bool");
392 }
393
394 #[test]
395 fn test_bit8_is_bytes() {
396 assert_eq!(map_type("bit", "bit(8)", TimeCrate::Chrono).path, "Vec<u8>");
397 }
398
399 #[test]
400 fn test_boolean_alias_is_bool() {
401 assert_eq!(
402 map_type("boolean", "boolean", TimeCrate::Chrono).path,
403 "bool"
404 );
405 }
406
407 #[test]
410 fn test_enum_placeholder() {
411 assert_eq!(
412 map_type("enum", "enum('a','b','c')", TimeCrate::Chrono).path,
413 "String"
414 );
415 }
416
417 #[test]
420 fn test_case_insensitive_int() {
421 assert_eq!(map_type("INT", "INT", TimeCrate::Chrono).path, "i32");
422 }
423
424 #[test]
425 fn test_case_insensitive_tinyint1() {
426 assert_eq!(
427 map_type("TINYINT", "TINYINT(1)", TimeCrate::Chrono).path,
428 "bool"
429 );
430 }
431
432 #[test]
435 fn test_geometry_fallback() {
436 assert_eq!(
437 map_type("geometry", "geometry", TimeCrate::Chrono).path,
438 "String"
439 );
440 }
441
442 #[test]
443 fn test_point_fallback() {
444 assert_eq!(map_type("point", "point", TimeCrate::Chrono).path, "String");
445 }
446
447 #[test]
450 fn test_resolve_enum_users_status() {
451 assert_eq!(resolve_enum_type("users", "status"), "UsersStatus");
452 }
453
454 #[test]
455 fn test_resolve_enum_user_roles_role_type() {
456 assert_eq!(
457 resolve_enum_type("user_roles", "role_type"),
458 "UserRolesRoleType"
459 );
460 }
461
462 #[test]
463 fn test_resolve_enum_short_names() {
464 assert_eq!(resolve_enum_type("t", "c"), "TC");
465 }
466
467 #[test]
468 fn test_resolve_enum_order_items_size() {
469 assert_eq!(resolve_enum_type("order_items", "size"), "OrderItemsSize");
470 }
471
472 #[test]
475 fn test_timestamp_time_crate() {
476 let rt = map_type("timestamp", "timestamp", TimeCrate::Time);
477 assert_eq!(rt.path, "OffsetDateTime");
478 assert!(rt
479 .needs_import
480 .as_ref()
481 .unwrap()
482 .contains("time::OffsetDateTime"));
483 }
484
485 #[test]
486 fn test_datetime_time_crate() {
487 let rt = map_type("datetime", "datetime", TimeCrate::Time);
488 assert_eq!(rt.path, "PrimitiveDateTime");
489 assert!(rt
490 .needs_import
491 .as_ref()
492 .unwrap()
493 .contains("time::PrimitiveDateTime"));
494 }
495
496 #[test]
497 fn test_date_time_crate() {
498 let rt = map_type("date", "date", TimeCrate::Time);
499 assert_eq!(rt.path, "Date");
500 assert!(rt.needs_import.as_ref().unwrap().contains("time::Date"));
501 }
502
503 #[test]
504 fn test_time_time_crate() {
505 let rt = map_type("time", "time", TimeCrate::Time);
506 assert_eq!(rt.path, "Time");
507 assert!(rt.needs_import.as_ref().unwrap().contains("time::Time"));
508 }
509}