use http::{Extensions, HeaderMap};
#[derive(Debug, Clone)]
pub struct TenantId(pub String);
#[derive(Debug, Clone)]
pub struct TenantConfig {
pub header_name: String,
pub required: bool,
pub fallback: Option<String>,
}
impl Default for TenantConfig {
fn default() -> Self {
Self {
header_name: "x-tenant-id".to_string(),
required: false,
fallback: None,
}
}
}
impl TenantConfig {
#[must_use]
pub fn tenant_from_headers(&self, headers: &HeaderMap) -> Option<TenantId> {
headers
.get(&self.header_name)
.and_then(|value| value.to_str().ok())
.map(|value| TenantId(value.to_owned()))
.or_else(|| self.fallback.clone().map(TenantId))
}
#[must_use]
pub const fn is_required(&self) -> bool {
self.required
}
}
pub fn set_tenant_in_extensions(extensions: &mut Extensions, tenant_id: impl Into<String>) {
extensions.insert(TenantId(tenant_id.into()));
}
pub fn tenant_from_extensions(extensions: &Extensions) -> Option<&TenantId> {
extensions.get::<TenantId>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tenant_config_default() {
let cfg = TenantConfig::default();
assert_eq!(cfg.header_name, "x-tenant-id");
assert!(!cfg.required);
assert!(cfg.fallback.is_none());
}
#[test]
fn test_tenant_config_with_fallback() {
let cfg = TenantConfig {
header_name: "x-tenant-id".to_string(),
required: false,
fallback: Some("default".to_string()),
};
assert_eq!(cfg.fallback, Some("default".to_string()));
}
#[test]
fn test_tenant_from_headers() {
let mut headers = HeaderMap::new();
headers.insert("x-tenant-id", "tenant-123".parse().unwrap());
let tenant = TenantConfig::default().tenant_from_headers(&headers);
assert_eq!(tenant.unwrap().0, "tenant-123");
}
#[test]
fn test_tenant_from_headers_uses_fallback() {
let cfg = TenantConfig {
fallback: Some("default".to_string()),
..Default::default()
};
assert_eq!(
cfg.tenant_from_headers(&HeaderMap::new()).unwrap().0,
"default"
);
}
#[test]
fn test_set_and_get_tenant_in_extensions() {
let mut ext = Extensions::new();
set_tenant_in_extensions(&mut ext, "org-42");
let tenant = tenant_from_extensions(&ext);
assert!(tenant.is_some());
assert_eq!(tenant.unwrap().0, "org-42");
}
#[test]
fn test_tenant_from_extensions_empty() {
let ext = Extensions::new();
assert!(tenant_from_extensions(&ext).is_none());
}
#[test]
fn test_set_tenant_overwrites_previous() {
let mut ext = Extensions::new();
set_tenant_in_extensions(&mut ext, "first");
set_tenant_in_extensions(&mut ext, "second");
assert_eq!(tenant_from_extensions(&ext).unwrap().0, "second");
}
}