1use crate::error::{Result, SchemaRiskError};
4use std::path::{Path, PathBuf};
5
6#[derive(Debug, Clone)]
8pub struct MigrationFile {
9 pub path: PathBuf,
10 pub name: String,
11 pub sql: String,
12}
13
14pub fn load_file(path: impl AsRef<Path>) -> Result<MigrationFile> {
16 let path = path.as_ref().to_path_buf();
17 if !path.exists() {
18 return Err(SchemaRiskError::InvalidMigration(format!(
19 "File not found: {}",
20 path.display()
21 )));
22 }
23
24 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
25
26 if !["sql", "psql", "pg"].contains(&ext) {
27 return Err(SchemaRiskError::InvalidMigration(format!(
28 "Expected a .sql file, got: {}",
29 path.display()
30 )));
31 }
32
33 let sql = std::fs::read_to_string(&path).map_err(SchemaRiskError::Io)?;
34 let name = path
35 .file_name()
36 .and_then(|n| n.to_str())
37 .unwrap_or("unknown")
38 .to_string();
39
40 Ok(MigrationFile { path, name, sql })
41}
42
43pub fn load_glob(pattern: &str) -> Result<Vec<MigrationFile>> {
45 let paths: Vec<PathBuf> = glob::glob(pattern)
46 .map_err(|e| SchemaRiskError::InvalidMigration(e.to_string()))?
47 .filter_map(|entry| entry.ok())
48 .filter(|p| {
49 p.extension()
50 .and_then(|e| e.to_str())
51 .map(|e| ["sql", "psql", "pg"].contains(&e))
52 .unwrap_or(false)
53 })
54 .collect();
55
56 if paths.is_empty() {
57 return Err(SchemaRiskError::NoFilesFound(pattern.to_string()));
58 }
59
60 paths.iter().map(load_file).collect()
61}