rdbi_codegen/config/
settings.rs1use config::{Config, Environment, File};
4use serde::{Deserialize, Serialize};
5use std::path::{Path, PathBuf};
6
7use super::defaults;
8use crate::error::{CodegenError, Result};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct CodegenConfig {
13 #[serde(default)]
15 pub schema_file: PathBuf,
16
17 #[serde(default = "default_include_tables")]
19 pub include_tables: String,
20
21 #[serde(default = "default_exclude_tables")]
23 pub exclude_tables: String,
24
25 #[serde(default = "default_generate_structs")]
27 pub generate_structs: bool,
28
29 #[serde(default = "default_generate_dao")]
31 pub generate_dao: bool,
32
33 #[serde(default = "default_output_structs_dir")]
35 pub output_structs_dir: PathBuf,
36
37 #[serde(default = "default_output_dao_dir")]
39 pub output_dao_dir: PathBuf,
40
41 #[serde(default = "default_models_module")]
43 pub models_module: String,
44
45 #[serde(default = "default_dao_module")]
47 pub dao_module: String,
48
49 #[serde(default = "default_dry_run")]
51 pub dry_run: bool,
52
53 #[serde(default)]
56 pub log_level: Option<String>,
57}
58
59fn default_include_tables() -> String {
61 defaults::INCLUDE_TABLES.to_string()
62}
63fn default_exclude_tables() -> String {
64 defaults::EXCLUDE_TABLES.to_string()
65}
66fn default_generate_structs() -> bool {
67 defaults::GENERATE_STRUCTS
68}
69fn default_generate_dao() -> bool {
70 defaults::GENERATE_DAO
71}
72fn default_output_structs_dir() -> PathBuf {
73 PathBuf::from(defaults::OUTPUT_STRUCTS_DIR)
74}
75fn default_output_dao_dir() -> PathBuf {
76 PathBuf::from(defaults::OUTPUT_DAO_DIR)
77}
78fn default_models_module() -> String {
79 defaults::MODELS_MODULE.to_string()
80}
81fn default_dao_module() -> String {
82 defaults::DAO_MODULE.to_string()
83}
84fn default_dry_run() -> bool {
85 defaults::DRY_RUN
86}
87
88impl Default for CodegenConfig {
89 fn default() -> Self {
90 Self {
91 schema_file: PathBuf::new(),
92 include_tables: default_include_tables(),
93 exclude_tables: default_exclude_tables(),
94 generate_structs: default_generate_structs(),
95 generate_dao: default_generate_dao(),
96 output_structs_dir: default_output_structs_dir(),
97 output_dao_dir: default_output_dao_dir(),
98 models_module: default_models_module(),
99 dao_module: default_dao_module(),
100 dry_run: default_dry_run(),
101 log_level: None,
102 }
103 }
104}
105
106impl CodegenConfig {
107 pub fn default_with_schema(schema_file: PathBuf) -> Self {
109 Self {
110 schema_file,
111 ..Default::default()
112 }
113 }
114
115 pub fn from_file(path: &Path) -> Result<Self> {
117 let content = std::fs::read_to_string(path)?;
118 let config: CodegenConfig = toml::from_str(&content).map_err(|e| {
119 CodegenError::ConfigError(format!(
120 "Failed to parse config file {}: {}",
121 path.display(),
122 e
123 ))
124 })?;
125 Ok(config)
126 }
127
128 pub fn load(config_path: Option<&Path>) -> Result<Self> {
130 let mut builder = Config::builder();
131
132 if let Some(path) = config_path {
134 builder = builder.add_source(File::from(path));
135 } else {
136 builder = builder.add_source(File::with_name("rdbi-codegen").required(false));
138 }
139
140 builder = builder.add_source(Environment::with_prefix("RDBI_CODEGEN").separator("_"));
142
143 let config: CodegenConfig = builder.build()?.try_deserialize()?;
144
145 Ok(config)
146 }
147
148 pub fn validate(&self) -> Result<()> {
150 if self.schema_file.as_os_str().is_empty() {
151 return Err(CodegenError::ValidationError(
152 "schema_file is required".into(),
153 ));
154 }
155
156 if !self.schema_file.exists() {
157 return Err(CodegenError::ValidationError(format!(
158 "Schema file not found: {}",
159 self.schema_file.display()
160 )));
161 }
162
163 if self.generate_structs && self.models_module.is_empty() {
164 return Err(CodegenError::ValidationError(
165 "models_module is required when generate_structs is true".into(),
166 ));
167 }
168
169 if self.generate_dao {
170 if !self.generate_structs {
171 return Err(CodegenError::ValidationError(
172 "generate_structs must be true when generate_dao is true (DAOs depend on structs)".into(),
173 ));
174 }
175 if self.dao_module.is_empty() {
176 return Err(CodegenError::ValidationError(
177 "dao_module is required when generate_dao is true".into(),
178 ));
179 }
180 }
181
182 Ok(())
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_default_config() {
192 let config = CodegenConfig::default();
193 assert_eq!(config.include_tables, "*");
194 assert!(config.generate_structs);
195 assert!(config.generate_dao);
196 assert!(config.log_level.is_none());
197 }
198
199 #[test]
200 fn test_validation_missing_schema() {
201 let config = CodegenConfig::default();
202 assert!(config.validate().is_err());
203 }
204
205 #[test]
206 fn test_config_with_log_level() {
207 let toml_content = r#"
208 schema_file = "test.sql"
209 log_level = "debug"
210 "#;
211 let config: CodegenConfig = toml::from_str(toml_content).unwrap();
212 assert_eq!(config.log_level, Some("debug".to_string()));
213 }
214}