use super::{FunctionsSubsystem, ServerSubsystems, StorageSubsystem};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum SubsystemBuildError {
#[error("{dependant} requires {dependency}: {reason}")]
MissingDependency {
dependant: &'static str,
dependency: &'static str,
reason: String,
},
}
#[derive(Default)]
pub struct ServerSubsystemsBuilder {
storage: Option<StorageSubsystem>,
functions: Option<FunctionsSubsystem>,
}
impl ServerSubsystemsBuilder {
#[must_use = "builder does nothing until .build() is called"]
pub fn new() -> Self {
Self::default()
}
#[must_use = "builder method returns modified builder"]
pub fn with_storage(mut self, subsystem: StorageSubsystem) -> Self {
self.storage = Some(subsystem);
self
}
#[must_use = "builder method returns modified builder"]
pub fn with_functions(mut self, subsystem: FunctionsSubsystem) -> Self {
self.functions = Some(subsystem);
self
}
pub fn build(self) -> Result<ServerSubsystems, SubsystemBuildError> {
self.validate()?;
Ok(ServerSubsystems {
storage: self.storage,
functions: self.functions,
})
}
fn validate(&self) -> Result<(), SubsystemBuildError> {
if let Some(functions) = &self.functions {
let has_storage_triggers = functions
.config
.definitions
.iter()
.any(|d| d.trigger.starts_with("after:storage:"));
if has_storage_triggers && self.storage.is_none() {
return Err(SubsystemBuildError::MissingDependency {
dependant: "functions",
dependency: "storage",
reason: "one or more function definitions use after:storage triggers but \
no storage subsystem is configured; either add a [storage] section \
to the compiled schema or remove the after:storage triggers"
.to_string(),
});
}
}
Ok(())
}
}