1use std::collections::BTreeMap;
6use std::path::Path;
7
8use fse_schema::Error;
9use serde::Deserialize;
10
11#[derive(Debug, Deserialize)]
12#[serde(default)]
13pub struct OrmConfig {
14 pub tables_dir: String,
16 pub migrations_dir: String,
19 pub snapshot_path: String,
21 pub database_url_env: String,
23 pub required_columns: BTreeMap<String, Vec<String>>,
26 pub modules: Vec<String>,
31}
32
33impl Default for OrmConfig {
34 fn default() -> Self {
35 Self {
36 tables_dir: "src/tables".into(),
37 migrations_dir: "migrations".into(),
38 snapshot_path: ".fse/schema.json".into(),
39 database_url_env: "DATABASE_URL".into(),
40 required_columns: BTreeMap::new(),
41 modules: Vec::new(),
42 }
43 }
44}
45
46#[derive(Debug, Default, Deserialize)]
47struct FseToml {
48 #[serde(default)]
49 orm: OrmConfig,
50}
51
52pub fn load(root: &Path) -> Result<OrmConfig, Error> {
53 let path = root.join("fse.toml");
54 if !path.exists() {
55 return Ok(OrmConfig::default());
56 }
57 let raw = std::fs::read_to_string(&path)
58 .map_err(|e| Error::new(format!("cannot read {}: {e}", path.display())))?;
59 let parsed: FseToml = toml::from_str(&raw).map_err(|e| Error::new(format!("fse.toml: {e}")))?;
60 Ok(parsed.orm)
61}
62
63pub fn resolve_database_url(
66 root: &Path,
67 cfg: &OrmConfig,
68 override_url: Option<&str>,
69) -> Result<String, Error> {
70 if let Some(url) = override_url {
71 return Ok(url.to_string());
72 }
73 dotenvy::from_path(root.join(".env")).ok();
74 std::env::var(&cfg.database_url_env)
75 .map_err(|_| Error::new(format!("{} is not set (env or .env)", cfg.database_url_env)))
76}