use std::path::PathBuf;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DomainDiscovery {
pub enabled: bool,
pub root_dir: String,
}
#[derive(Debug, Clone)]
pub struct Domain {
pub name: String,
pub path: PathBuf,
}
impl DomainDiscovery {
pub fn resolve_domains(&self) -> Result<Vec<Domain>> {
if !self.enabled {
return Ok(Vec::new());
}
let root = PathBuf::from(&self.root_dir);
if !root.is_dir() {
anyhow::bail!("Domain discovery root not found: {}", self.root_dir);
}
let mut domains = Vec::new();
for entry in std::fs::read_dir(&root)
.context(format!("Failed to read domain root: {}", self.root_dir))?
{
let entry = entry.context("Failed to read directory entry")?;
let path = entry.path();
if path.is_dir() {
let name = path
.file_name()
.and_then(|n| n.to_str())
.map(std::string::ToString::to_string)
.ok_or_else(|| anyhow::anyhow!("Invalid domain name: {}", path.display()))?;
domains.push(Domain { name, path });
}
}
domains.sort_by(|a, b| a.name.cmp(&b.name));
Ok(domains)
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct SchemaIncludes {
pub types: Vec<String>,
pub queries: Vec<String>,
pub mutations: Vec<String>,
}
impl SchemaIncludes {
pub fn is_empty(&self) -> bool {
self.types.is_empty() && self.queries.is_empty() && self.mutations.is_empty()
}
pub fn resolve_globs(&self) -> Result<ResolvedIncludes> {
use glob::glob as glob_pattern;
let mut type_paths = Vec::new();
let mut query_paths = Vec::new();
let mut mutation_paths = Vec::new();
for pattern in &self.types {
for entry in glob_pattern(pattern)
.context(format!("Invalid glob pattern for types: {pattern}"))?
{
match entry {
Ok(path) => type_paths.push(path),
Err(e) => {
anyhow::bail!("Error resolving type glob pattern '{pattern}': {e}");
},
}
}
}
for pattern in &self.queries {
for entry in glob_pattern(pattern)
.context(format!("Invalid glob pattern for queries: {pattern}"))?
{
match entry {
Ok(path) => query_paths.push(path),
Err(e) => {
anyhow::bail!("Error resolving query glob pattern '{pattern}': {e}");
},
}
}
}
for pattern in &self.mutations {
for entry in glob_pattern(pattern)
.context(format!("Invalid glob pattern for mutations: {pattern}"))?
{
match entry {
Ok(path) => mutation_paths.push(path),
Err(e) => {
anyhow::bail!("Error resolving mutation glob pattern '{pattern}': {e}");
},
}
}
}
type_paths.sort();
query_paths.sort();
mutation_paths.sort();
type_paths.dedup();
query_paths.dedup();
mutation_paths.dedup();
Ok(ResolvedIncludes {
types: type_paths,
queries: query_paths,
mutations: mutation_paths,
})
}
}
#[derive(Debug, Clone)]
pub struct ResolvedIncludes {
pub types: Vec<PathBuf>,
pub queries: Vec<PathBuf>,
pub mutations: Vec<PathBuf>,
}