use thiserror::Error;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error(transparent)]
FluentUriParse(#[from] fluent_uri::ParseError),
#[error(transparent)]
JsonschemaValidation(#[from] Box<jsonschema::ValidationError<'static>>),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error("json value is not an object or an array")]
ScalarJson(serde_json::Value),
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
#[error(transparent)]
Stac(#[from] stac::Error),
#[error("{} validation error(s)", .0.len())]
Validation(Vec<Validation>),
}
#[derive(Debug)]
pub struct Validation {
id: Option<String>,
r#type: Option<stac::Type>,
error: jsonschema::ValidationError<'static>,
}
impl Validation {
pub(crate) fn new(
error: jsonschema::ValidationError<'_>,
value: Option<&serde_json::Value>,
) -> Validation {
let mut id = None;
let mut r#type = None;
if let Some(value) = value.and_then(|v| v.as_object()) {
id = value.get("id").and_then(|v| v.as_str()).map(String::from);
r#type = value
.get("type")
.and_then(|v| v.as_str())
.and_then(|s| s.parse::<stac::Type>().ok());
}
Validation {
id,
r#type,
error: error.to_owned(),
}
}
pub fn into_json(self) -> serde_json::Value {
serde_json::json!({
"id": self.id,
"type": self.r#type,
"error": self.error.to_string(),
})
}
}
impl super::Error {
pub(crate) fn from_validation_errors<'a, I>(
errors: I,
value: Option<&serde_json::Value>,
) -> super::Error
where
I: Iterator<Item = jsonschema::ValidationError<'a>>,
{
super::Error::Validation(errors.map(|error| Validation::new(error, value)).collect())
}
}
impl std::fmt::Display for Validation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(r#type) = self.r#type {
if let Some(id) = self.id.as_ref() {
write!(f, "{}[id={id}]: {}", r#type, self.error)
} else {
write!(f, "{}: {}", r#type, self.error)
}
} else if let Some(id) = self.id.as_ref() {
write!(f, "[id={id}]: {}", self.error)
} else {
write!(f, "{}", self.error)
}
}
}