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