scythe_codegen/
resolve.rs1use scythe_backend::manifest::BackendManifest;
2use scythe_backend::naming::to_snake_case;
3use scythe_backend::types::resolve_type_pair;
4
5use scythe_core::analyzer::{AnalyzedColumn, AnalyzedParam};
6use scythe_core::errors::{ErrorCode, ScytheError};
7
8use crate::backend_trait::{ResolvedColumn, ResolvedParam};
9
10pub fn resolve_columns(
12 columns: &[AnalyzedColumn],
13 manifest: &BackendManifest,
14) -> Result<Vec<ResolvedColumn>, ScytheError> {
15 columns
16 .iter()
17 .map(|col| {
18 let (full_type, lang_type) =
19 resolve_type_pair(&col.neutral_type, manifest, col.nullable)
20 .map(|(f, l)| (f.into_owned(), l.into_owned()))
21 .map_err(|e| {
22 ScytheError::new(
23 ErrorCode::InternalError,
24 format!("type resolution failed for column '{}': {}", col.name, e),
25 )
26 })?;
27 Ok(ResolvedColumn {
28 name: col.name.clone(),
29 field_name: to_snake_case(&col.name).into_owned(),
30 lang_type,
31 full_type,
32 neutral_type: col.neutral_type.clone(),
33 nullable: col.nullable,
34 })
35 })
36 .collect()
37}
38
39pub fn resolve_params(
41 params: &[AnalyzedParam],
42 manifest: &BackendManifest,
43) -> Result<Vec<ResolvedParam>, ScytheError> {
44 params
45 .iter()
46 .map(|param| {
47 let (full_type, lang_type) =
48 resolve_type_pair(¶m.neutral_type, manifest, param.nullable)
49 .map(|(f, l)| (f.into_owned(), l.into_owned()))
50 .map_err(|e| {
51 ScytheError::new(
52 ErrorCode::InternalError,
53 format!("type resolution failed for param '{}': {}", param.name, e),
54 )
55 })?;
56 let borrowed_type = param_type_to_borrowed(&full_type);
57 Ok(ResolvedParam {
58 name: param.name.clone(),
59 field_name: to_snake_case(¶m.name).into_owned(),
60 lang_type,
61 full_type,
62 borrowed_type,
63 neutral_type: param.neutral_type.clone(),
64 nullable: param.nullable,
65 })
66 })
67 .collect()
68}
69
70pub fn param_type_to_borrowed(rust_type: &str) -> String {
73 let copy_types = ["bool", "i16", "i32", "i64", "f32", "f64", "u64"];
75 if copy_types.contains(&rust_type) {
76 return rust_type.to_string();
77 }
78 if rust_type == "String" {
80 return "&str".to_string();
81 }
82 if let Some(inner) = rust_type
84 .strip_prefix("Option<")
85 .and_then(|s| s.strip_suffix('>'))
86 {
87 let borrowed_inner = param_type_to_borrowed(inner);
88 return format!("Option<{}>", borrowed_inner);
89 }
90 if let Some(inner) = rust_type
92 .strip_prefix("Vec<")
93 .and_then(|s| s.strip_suffix('>'))
94 {
95 return format!("&[{}]", inner);
96 }
97 format!("&{}", rust_type)
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_param_type_to_borrowed_string() {
107 assert_eq!(param_type_to_borrowed("String"), "&str");
108 }
109
110 #[test]
111 fn test_param_type_to_borrowed_vec() {
112 assert_eq!(param_type_to_borrowed("Vec<i32>"), "&[i32]");
113 assert_eq!(param_type_to_borrowed("Vec<String>"), "&[String]");
114 }
115
116 #[test]
117 fn test_param_type_to_borrowed_passthrough() {
118 assert_eq!(param_type_to_borrowed("i32"), "i32");
119 assert_eq!(param_type_to_borrowed("i64"), "i64");
120 assert_eq!(param_type_to_borrowed("bool"), "bool");
121 assert_eq!(param_type_to_borrowed("f64"), "f64");
122 }
123
124 #[test]
125 fn test_param_type_to_borrowed_option_string() {
126 assert_eq!(param_type_to_borrowed("Option<String>"), "Option<&str>");
127 }
128
129 #[test]
130 fn test_param_type_to_borrowed_option_copy() {
131 assert_eq!(param_type_to_borrowed("Option<i32>"), "Option<i32>");
132 }
133
134 #[test]
135 fn test_param_type_to_borrowed_other() {
136 assert_eq!(param_type_to_borrowed("Uuid"), "&Uuid");
137 assert_eq!(param_type_to_borrowed("NaiveDateTime"), "&NaiveDateTime");
138 }
139}