yauth_migration/
config.rs1use serde::{Deserialize, Serialize};
7use std::path::Path;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct YAuthConfig {
12 pub migration: MigrationConfig,
13 pub plugins: PluginsConfig,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct MigrationConfig {
19 pub orm: crate::Orm,
21 pub dialect: String,
23 #[serde(default = "default_migrations_dir")]
25 pub migrations_dir: String,
26 #[serde(default = "default_queries_dir")]
28 pub queries_dir: String,
29 #[serde(default)]
31 pub schema: Option<String>,
32 #[serde(default = "default_table_prefix")]
34 pub table_prefix: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct PluginsConfig {
40 pub enabled: Vec<String>,
42}
43
44fn default_migrations_dir() -> String {
45 "migrations".to_string()
46}
47
48fn default_queries_dir() -> String {
49 "queries".to_string()
50}
51
52fn default_table_prefix() -> String {
53 "yauth_".to_string()
54}
55
56impl YAuthConfig {
57 pub fn load(path: &Path) -> Result<Self, ConfigError> {
59 let contents = std::fs::read_to_string(path)
60 .map_err(|e| ConfigError::Io(path.display().to_string(), e))?;
61 let config: Self = toml::from_str(&contents)
62 .map_err(|e| ConfigError::Parse(path.display().to_string(), e))?;
63 config.validate()?;
64 Ok(config)
65 }
66
67 pub fn save(&self, path: &Path) -> Result<(), ConfigError> {
69 let contents =
70 toml::to_string_pretty(self).map_err(|e| ConfigError::Serialize(e.to_string()))?;
71 std::fs::write(path, contents)
72 .map_err(|e| ConfigError::Io(path.display().to_string(), e))?;
73 Ok(())
74 }
75
76 pub fn validate(&self) -> Result<(), ConfigError> {
78 if self.migration.dialect.parse::<crate::Dialect>().is_err() {
80 return Err(ConfigError::InvalidValue(format!(
81 "unknown dialect: '{}'",
82 self.migration.dialect
83 )));
84 }
85
86 for plugin in &self.plugins.enabled {
88 if !crate::is_known_plugin(plugin) {
89 return Err(ConfigError::InvalidValue(format!(
90 "unknown plugin: '{plugin}'"
91 )));
92 }
93 }
94
95 if self.migration.table_prefix.is_empty() {
97 return Err(ConfigError::InvalidValue(
98 "table_prefix must not be empty".to_string(),
99 ));
100 }
101
102 Ok(())
103 }
104
105 pub fn new(orm: crate::Orm, dialect: &str, plugins: Vec<String>) -> Self {
107 Self {
108 migration: MigrationConfig {
109 orm,
110 dialect: dialect.to_string(),
111 migrations_dir: default_migrations_dir(),
112 queries_dir: default_queries_dir(),
113 schema: None,
114 table_prefix: default_table_prefix(),
115 },
116 plugins: PluginsConfig { enabled: plugins },
117 }
118 }
119}
120
121#[derive(Debug)]
123pub enum ConfigError {
124 Io(String, std::io::Error),
125 Parse(String, toml::de::Error),
126 Serialize(String),
127 InvalidValue(String),
128}
129
130impl std::fmt::Display for ConfigError {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 ConfigError::Io(path, e) => write!(f, "I/O error with '{path}': {e}"),
134 ConfigError::Parse(path, e) => write!(f, "parse error in '{path}': {e}"),
135 ConfigError::Serialize(e) => write!(f, "serialization error: {e}"),
136 ConfigError::InvalidValue(msg) => write!(f, "invalid config: {msg}"),
137 }
138 }
139}
140
141impl std::error::Error for ConfigError {}