use std::collections::HashMap;
use appcore_core::{RuntimeError, RuntimeResult};
use crate::api::{ApiRequest, ApiResponse};
use crate::command_endpoint::CommandEndpoint;
use crate::query_endpoint::{QueryEndpoint, QueryName};
#[derive(Default)]
pub struct ApiRouter {
command_endpoint: Option<Box<dyn CommandEndpoint>>,
queries: HashMap<QueryName, Box<dyn QueryEndpoint>>,
}
impl ApiRouter {
pub fn new() -> Self {
Self::default()
}
pub fn set_command_endpoint<E: CommandEndpoint + 'static>(&mut self, endpoint: E) {
self.command_endpoint = Some(Box::new(endpoint));
}
pub fn register_query<E: QueryEndpoint + 'static>(&mut self, endpoint: E) -> RuntimeResult<()> {
let name = endpoint.query_name().clone();
if self.queries.contains_key(&name) {
return Err(RuntimeError::RegistryItemAlreadyRegistered {
kind: "query",
name: name.as_str().to_string(),
});
}
self.queries.insert(name, Box::new(endpoint));
Ok(())
}
pub fn has_query(&self, name: &QueryName) -> bool {
self.queries.contains_key(name)
}
pub fn query_names(&self) -> Vec<QueryName> {
let mut names = self.queries.keys().cloned().collect::<Vec<_>>();
names.sort_by(|left, right| left.as_str().cmp(right.as_str()));
names
}
pub fn dispatch_query(
&self,
name: &QueryName,
request: ApiRequest,
) -> RuntimeResult<ApiResponse> {
let Some(endpoint) = self.queries.get(name) else {
return Err(RuntimeError::RegistryItemNotFound {
kind: "query",
name: name.as_str().to_string(),
});
};
endpoint.handle_query(request)
}
pub fn dispatch_command(&self, request: ApiRequest) -> RuntimeResult<ApiResponse> {
let Some(endpoint) = &self.command_endpoint else {
return Err(RuntimeError::MissingConfiguration {
name: "command_endpoint",
});
};
endpoint.handle_command(request)
}
}
#[cfg(test)]
#[path = "router_tests.rs"]
mod tests;