fraiseql_cli/config/toml_schema/
domain.rs1use std::path::PathBuf;
4
5use anyhow::{Context, Result};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Deserialize, Serialize)]
30#[serde(default, deny_unknown_fields)]
31pub struct DomainDiscovery {
32 pub enabled: bool,
34 pub root_dir: String,
36}
37
38#[derive(Debug, Clone)]
40pub struct Domain {
41 pub name: String,
43 pub path: PathBuf,
45}
46
47impl DomainDiscovery {
48 pub fn resolve_domains(&self) -> Result<Vec<Domain>> {
56 if !self.enabled {
57 return Ok(Vec::new());
58 }
59
60 let root = PathBuf::from(&self.root_dir);
61 if !root.is_dir() {
62 anyhow::bail!("Domain discovery root not found: {}", self.root_dir);
63 }
64
65 let mut domains = Vec::new();
66
67 for entry in std::fs::read_dir(&root)
68 .context(format!("Failed to read domain root: {}", self.root_dir))?
69 {
70 let entry = entry.context("Failed to read directory entry")?;
71 let path = entry.path();
72
73 if path.is_dir() {
74 let name = path
75 .file_name()
76 .and_then(|n| n.to_str())
77 .map(std::string::ToString::to_string)
78 .ok_or_else(|| anyhow::anyhow!("Invalid domain name: {}", path.display()))?;
79
80 domains.push(Domain { name, path });
81 }
82 }
83
84 domains.sort_by(|a, b| a.name.cmp(&b.name));
86
87 Ok(domains)
88 }
89}
90
91#[derive(Debug, Clone, Default, Deserialize, Serialize)]
101#[serde(default, deny_unknown_fields)]
102pub struct SchemaIncludes {
103 pub types: Vec<String>,
105 pub queries: Vec<String>,
107 pub mutations: Vec<String>,
109}
110
111impl SchemaIncludes {
112 pub fn is_empty(&self) -> bool {
114 self.types.is_empty() && self.queries.is_empty() && self.mutations.is_empty()
115 }
116
117 pub fn resolve_globs(&self) -> Result<ResolvedIncludes> {
127 use glob::glob as glob_pattern;
128
129 let mut type_paths = Vec::new();
130 let mut query_paths = Vec::new();
131 let mut mutation_paths = Vec::new();
132
133 for pattern in &self.types {
135 for entry in glob_pattern(pattern)
136 .context(format!("Invalid glob pattern for types: {pattern}"))?
137 {
138 match entry {
139 Ok(path) => type_paths.push(path),
140 Err(e) => {
141 anyhow::bail!("Error resolving type glob pattern '{pattern}': {e}");
142 },
143 }
144 }
145 }
146
147 for pattern in &self.queries {
149 for entry in glob_pattern(pattern)
150 .context(format!("Invalid glob pattern for queries: {pattern}"))?
151 {
152 match entry {
153 Ok(path) => query_paths.push(path),
154 Err(e) => {
155 anyhow::bail!("Error resolving query glob pattern '{pattern}': {e}");
156 },
157 }
158 }
159 }
160
161 for pattern in &self.mutations {
163 for entry in glob_pattern(pattern)
164 .context(format!("Invalid glob pattern for mutations: {pattern}"))?
165 {
166 match entry {
167 Ok(path) => mutation_paths.push(path),
168 Err(e) => {
169 anyhow::bail!("Error resolving mutation glob pattern '{pattern}': {e}");
170 },
171 }
172 }
173 }
174
175 type_paths.sort();
177 query_paths.sort();
178 mutation_paths.sort();
179
180 type_paths.dedup();
182 query_paths.dedup();
183 mutation_paths.dedup();
184
185 Ok(ResolvedIncludes {
186 types: type_paths,
187 queries: query_paths,
188 mutations: mutation_paths,
189 })
190 }
191}
192
193#[derive(Debug, Clone)]
195pub struct ResolvedIncludes {
196 pub types: Vec<PathBuf>,
198 pub queries: Vec<PathBuf>,
200 pub mutations: Vec<PathBuf>,
202}