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" => {
53 RustType::with_import("Decimal", "use rust_decimal::Decimal;")
54 }
55 "varchar" | "char" | "text" | "tinytext" | "mediumtext" | "longtext" | "enum" | "set" => {
56 RustType::simple("String")
57 }
58 "binary" | "varbinary" | "blob" | "tinyblob" | "mediumblob" | "longblob" => {
59 RustType::simple("Vec<u8>")
60 }
61 "date" => match time_crate {
62 TimeCrate::Chrono => RustType::with_import("NaiveDate", "use chrono::NaiveDate;"),
63 TimeCrate::Time => RustType::with_import("Date", "use time::Date;"),
64 },
65 "time" => match time_crate {
66 TimeCrate::Chrono => RustType::with_import("NaiveTime", "use chrono::NaiveTime;"),
67 TimeCrate::Time => RustType::with_import("Time", "use time::Time;"),
68 },
69 "datetime" => match time_crate {
70 TimeCrate::Chrono => RustType::with_import("NaiveDateTime", "use chrono::NaiveDateTime;"),
71 TimeCrate::Time => RustType::with_import("PrimitiveDateTime", "use time::PrimitiveDateTime;"),
72 },
73 "timestamp" => match time_crate {
74 TimeCrate::Chrono => RustType::with_import("DateTime<Utc>", "use chrono::{DateTime, Utc};"),
75 TimeCrate::Time => RustType::with_import("OffsetDateTime", "use time::OffsetDateTime;"),
76 },
77 "json" => RustType::with_import("Value", "use serde_json::Value;"),
78 "year" => RustType::simple("i16"),
79 "bit" => RustType::simple("Vec<u8>"),
80 _ => RustType::simple("String"),
81 }
82}
83
84pub fn resolve_enum_type(table_name: &str, column_name: &str) -> String {
86 let enum_name = format!("{}_{}", table_name, column_name);
87 enum_name.to_upper_camel_case()
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::cli::TimeCrate;
94
95 #[test]
98 fn test_tinyint1_is_bool() {
99 assert_eq!(map_type("tinyint", "tinyint(1)", TimeCrate::Chrono).path, "bool");
100 }
101
102 #[test]
103 fn test_tinyint_signed() {
104 assert_eq!(map_type("tinyint", "tinyint", TimeCrate::Chrono).path, "i8");
105 }
106
107 #[test]
108 fn test_tinyint_unsigned() {
109 assert_eq!(map_type("tinyint", "tinyint unsigned", TimeCrate::Chrono).path, "u8");
110 }
111
112 #[test]
113 fn test_tinyint3_signed() {
114 assert_eq!(map_type("tinyint", "tinyint(3)", TimeCrate::Chrono).path, "i8");
115 }
116
117 #[test]
118 fn test_tinyint3_unsigned() {
119 assert_eq!(map_type("tinyint", "tinyint(3) unsigned", TimeCrate::Chrono).path, "u8");
120 }
121
122 #[test]
125 fn test_smallint_signed() {
126 assert_eq!(map_type("smallint", "smallint", TimeCrate::Chrono).path, "i16");
127 }
128
129 #[test]
130 fn test_smallint_unsigned() {
131 assert_eq!(map_type("smallint", "smallint unsigned", TimeCrate::Chrono).path, "u16");
132 }
133
134 #[test]
137 fn test_int_signed() {
138 assert_eq!(map_type("int", "int", TimeCrate::Chrono).path, "i32");
139 }
140
141 #[test]
142 fn test_int_unsigned() {
143 assert_eq!(map_type("int", "int unsigned", TimeCrate::Chrono).path, "u32");
144 }
145
146 #[test]
147 fn test_mediumint_signed() {
148 assert_eq!(map_type("mediumint", "mediumint", TimeCrate::Chrono).path, "i32");
149 }
150
151 #[test]
152 fn test_mediumint_unsigned() {
153 assert_eq!(map_type("mediumint", "mediumint unsigned", TimeCrate::Chrono).path, "u32");
154 }
155
156 #[test]
157 fn test_int11_signed() {
158 assert_eq!(map_type("int", "int(11)", TimeCrate::Chrono).path, "i32");
159 }
160
161 #[test]
162 fn test_int11_unsigned() {
163 assert_eq!(map_type("int", "int(11) unsigned", TimeCrate::Chrono).path, "u32");
164 }
165
166 #[test]
169 fn test_bigint_signed() {
170 assert_eq!(map_type("bigint", "bigint", TimeCrate::Chrono).path, "i64");
171 }
172
173 #[test]
174 fn test_bigint_unsigned() {
175 assert_eq!(map_type("bigint", "bigint unsigned", TimeCrate::Chrono).path, "u64");
176 }
177
178 #[test]
179 fn test_bigint20_signed() {
180 assert_eq!(map_type("bigint", "bigint(20)", TimeCrate::Chrono).path, "i64");
181 }
182
183 #[test]
186 fn test_float() {
187 assert_eq!(map_type("float", "float", TimeCrate::Chrono).path, "f32");
188 }
189
190 #[test]
191 fn test_double() {
192 assert_eq!(map_type("double", "double", TimeCrate::Chrono).path, "f64");
193 }
194
195 #[test]
198 fn test_decimal() {
199 let rt = map_type("decimal", "decimal(10,2)", TimeCrate::Chrono);
200 assert_eq!(rt.path, "Decimal");
201 assert!(rt.needs_import.as_ref().unwrap().contains("rust_decimal"));
202 }
203
204 #[test]
205 fn test_numeric() {
206 let rt = map_type("numeric", "numeric", TimeCrate::Chrono);
207 assert_eq!(rt.path, "Decimal");
208 assert!(rt.needs_import.is_some());
209 }
210
211 #[test]
214 fn test_varchar() {
215 assert_eq!(map_type("varchar", "varchar(255)", TimeCrate::Chrono).path, "String");
216 }
217
218 #[test]
219 fn test_char() {
220 assert_eq!(map_type("char", "char(1)", TimeCrate::Chrono).path, "String");
221 }
222
223 #[test]
224 fn test_text() {
225 assert_eq!(map_type("text", "text", TimeCrate::Chrono).path, "String");
226 }
227
228 #[test]
229 fn test_tinytext() {
230 assert_eq!(map_type("tinytext", "tinytext", TimeCrate::Chrono).path, "String");
231 }
232
233 #[test]
234 fn test_mediumtext() {
235 assert_eq!(map_type("mediumtext", "mediumtext", TimeCrate::Chrono).path, "String");
236 }
237
238 #[test]
239 fn test_longtext() {
240 assert_eq!(map_type("longtext", "longtext", TimeCrate::Chrono).path, "String");
241 }
242
243 #[test]
244 fn test_set() {
245 assert_eq!(map_type("set", "set('a','b')", TimeCrate::Chrono).path, "String");
246 }
247
248 #[test]
251 fn test_binary() {
252 assert_eq!(map_type("binary", "binary(16)", TimeCrate::Chrono).path, "Vec<u8>");
253 }
254
255 #[test]
256 fn test_varbinary() {
257 assert_eq!(map_type("varbinary", "varbinary(255)", TimeCrate::Chrono).path, "Vec<u8>");
258 }
259
260 #[test]
261 fn test_blob() {
262 assert_eq!(map_type("blob", "blob", TimeCrate::Chrono).path, "Vec<u8>");
263 }
264
265 #[test]
266 fn test_tinyblob() {
267 assert_eq!(map_type("tinyblob", "tinyblob", TimeCrate::Chrono).path, "Vec<u8>");
268 }
269
270 #[test]
273 fn test_date() {
274 let rt = map_type("date", "date", TimeCrate::Chrono);
275 assert_eq!(rt.path, "NaiveDate");
276 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
277 }
278
279 #[test]
280 fn test_time() {
281 let rt = map_type("time", "time", TimeCrate::Chrono);
282 assert_eq!(rt.path, "NaiveTime");
283 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
284 }
285
286 #[test]
287 fn test_datetime() {
288 let rt = map_type("datetime", "datetime", TimeCrate::Chrono);
289 assert_eq!(rt.path, "NaiveDateTime");
290 assert!(rt.needs_import.is_some());
291 }
292
293 #[test]
294 fn test_timestamp() {
295 let rt = map_type("timestamp", "timestamp", TimeCrate::Chrono);
296 assert_eq!(rt.path, "DateTime<Utc>");
297 assert!(rt.needs_import.as_ref().unwrap().contains("chrono"));
298 }
299
300 #[test]
303 fn test_json() {
304 let rt = map_type("json", "json", TimeCrate::Chrono);
305 assert_eq!(rt.path, "Value");
306 assert!(rt.needs_import.as_ref().unwrap().contains("serde_json"));
307 }
308
309 #[test]
310 fn test_year() {
311 assert_eq!(map_type("year", "year", TimeCrate::Chrono).path, "i16");
312 }
313
314 #[test]
315 fn test_bit() {
316 assert_eq!(map_type("bit", "bit(1)", TimeCrate::Chrono).path, "Vec<u8>");
317 }
318
319 #[test]
322 fn test_enum_placeholder() {
323 assert_eq!(map_type("enum", "enum('a','b','c')", TimeCrate::Chrono).path, "String");
324 }
325
326 #[test]
329 fn test_case_insensitive_int() {
330 assert_eq!(map_type("INT", "INT", TimeCrate::Chrono).path, "i32");
331 }
332
333 #[test]
334 fn test_case_insensitive_tinyint1() {
335 assert_eq!(map_type("TINYINT", "TINYINT(1)", TimeCrate::Chrono).path, "bool");
336 }
337
338 #[test]
341 fn test_geometry_fallback() {
342 assert_eq!(map_type("geometry", "geometry", TimeCrate::Chrono).path, "String");
343 }
344
345 #[test]
346 fn test_point_fallback() {
347 assert_eq!(map_type("point", "point", TimeCrate::Chrono).path, "String");
348 }
349
350 #[test]
353 fn test_resolve_enum_users_status() {
354 assert_eq!(resolve_enum_type("users", "status"), "UsersStatus");
355 }
356
357 #[test]
358 fn test_resolve_enum_user_roles_role_type() {
359 assert_eq!(resolve_enum_type("user_roles", "role_type"), "UserRolesRoleType");
360 }
361
362 #[test]
363 fn test_resolve_enum_short_names() {
364 assert_eq!(resolve_enum_type("t", "c"), "TC");
365 }
366
367 #[test]
368 fn test_resolve_enum_order_items_size() {
369 assert_eq!(resolve_enum_type("order_items", "size"), "OrderItemsSize");
370 }
371
372 #[test]
375 fn test_timestamp_time_crate() {
376 let rt = map_type("timestamp", "timestamp", TimeCrate::Time);
377 assert_eq!(rt.path, "OffsetDateTime");
378 assert!(rt.needs_import.as_ref().unwrap().contains("time::OffsetDateTime"));
379 }
380
381 #[test]
382 fn test_datetime_time_crate() {
383 let rt = map_type("datetime", "datetime", TimeCrate::Time);
384 assert_eq!(rt.path, "PrimitiveDateTime");
385 assert!(rt.needs_import.as_ref().unwrap().contains("time::PrimitiveDateTime"));
386 }
387
388 #[test]
389 fn test_date_time_crate() {
390 let rt = map_type("date", "date", TimeCrate::Time);
391 assert_eq!(rt.path, "Date");
392 assert!(rt.needs_import.as_ref().unwrap().contains("time::Date"));
393 }
394
395 #[test]
396 fn test_time_time_crate() {
397 let rt = map_type("time", "time", TimeCrate::Time);
398 assert_eq!(rt.path, "Time");
399 assert!(rt.needs_import.as_ref().unwrap().contains("time::Time"));
400 }
401}