use osproxy_core::{ErrorCode, PartitionId};
use thiserror::Error;
use crate::rules::PartitionKeySpecKind;
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum SpiError {
#[error("partition could not be resolved (tried: {tried:?})")]
PartitionUnresolved {
tried: Vec<PartitionKeySpecKind>,
},
#[error("no placement exists for partition")]
PlacementMissing {
partition: PartitionId,
},
#[error("placement lookup backend unavailable (retryable={retryable})")]
PlacementBackend {
retryable: bool,
},
#[error("endpoint not supported for tenancy rewrite")]
UnsupportedEndpoint {
endpoint: osproxy_core::EndpointKind,
},
#[error("principal is missing an attribute required by an injected field")]
PrincipalAttrMissing {
attr: String,
},
#[error("request is missing a header required by an injected field")]
HeaderMissing {
header: String,
},
#[error("shared-index doc-id rule must reference the partition id")]
IdRuleMissingPartition,
}
impl SpiError {
#[must_use]
pub fn code(&self) -> ErrorCode {
match self {
Self::PartitionUnresolved { .. } => ErrorCode::PartitionUnresolved,
Self::PlacementMissing { .. } => ErrorCode::PlacementMissing,
Self::PlacementBackend { .. } => ErrorCode::PlacementBackendUnavailable,
Self::UnsupportedEndpoint { .. }
| Self::IdRuleMissingPartition
| Self::PrincipalAttrMissing { .. }
| Self::HeaderMissing { .. } => ErrorCode::UnsupportedEndpoint,
}
}
#[must_use]
pub fn retryable(&self) -> bool {
matches!(self, Self::PlacementBackend { retryable: true })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn codes_map_to_core_taxonomy() {
assert_eq!(
SpiError::PartitionUnresolved { tried: vec![] }.code(),
ErrorCode::PartitionUnresolved
);
assert_eq!(
SpiError::PlacementMissing {
partition: PartitionId::from("p")
}
.code(),
ErrorCode::PlacementMissing
);
}
#[test]
fn only_backend_unavailable_is_retryable() {
assert!(SpiError::PlacementBackend { retryable: true }.retryable());
assert!(!SpiError::PlacementBackend { retryable: false }.retryable());
assert!(!SpiError::PlacementMissing {
partition: PartitionId::from("p")
}
.retryable());
}
}