fraiseql_server/schema/
loader.rs1use std::path::{Path, PathBuf};
4
5use fraiseql_core::schema::CompiledSchema;
6use tracing::{debug, info};
7
8#[derive(Debug, thiserror::Error)]
10pub enum SchemaLoadError {
11 #[error("Schema file not found: {0}")]
13 NotFound(PathBuf),
14
15 #[error("Failed to read schema file: {0}")]
17 IoError(#[from] std::io::Error),
18
19 #[error("Failed to parse schema JSON: {0}")]
21 ParseError(#[from] serde_json::Error),
22
23 #[error("Invalid schema: {0}")]
25 ValidationError(String),
26}
27
28#[derive(Debug, Clone)]
33pub struct CompiledSchemaLoader {
34 path: PathBuf,
36}
37
38impl CompiledSchemaLoader {
39 #[must_use]
52 pub fn new<P: AsRef<Path>>(path: P) -> Self {
53 Self {
54 path: path.as_ref().to_path_buf(),
55 }
56 }
57
58 pub async fn load(&self) -> Result<CompiledSchema, SchemaLoadError> {
77 info!(path = %self.path.display(), "Loading compiled schema");
78
79 if !self.path.exists() {
81 return Err(SchemaLoadError::NotFound(self.path.clone()));
82 }
83
84 let contents =
86 tokio::fs::read_to_string(&self.path).await.map_err(SchemaLoadError::IoError)?;
87
88 debug!(
89 path = %self.path.display(),
90 size_bytes = contents.len(),
91 "Schema file read successfully"
92 );
93
94 serde_json::from_str::<serde_json::Value>(&contents)?;
96
97 let schema = CompiledSchema::from_json(&contents)
99 .map_err(|e| SchemaLoadError::ValidationError(e.to_string()))?;
100
101 info!(path = %self.path.display(), "Schema loaded successfully");
102
103 Ok(schema)
104 }
105
106 #[must_use]
108 pub fn path(&self) -> &Path {
109 &self.path
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use std::io::Write;
116
117 use tempfile::NamedTempFile;
118
119 use super::*;
120
121 #[tokio::test]
122 async fn test_loader_not_found() {
123 let loader = CompiledSchemaLoader::new("/nonexistent/path/schema.json");
124 let result = loader.load().await;
125 assert!(matches!(result, Err(SchemaLoadError::NotFound(_))));
126 }
127
128 #[tokio::test]
129 async fn test_loader_invalid_json() {
130 let mut file = NamedTempFile::new().unwrap();
131 writeln!(file, "{{invalid json").unwrap();
132 file.flush().unwrap();
133
134 let loader = CompiledSchemaLoader::new(file.path());
135 let result = loader.load().await;
136 assert!(matches!(result, Err(SchemaLoadError::ParseError(_))));
137 }
138}