|
1 | 1 | use crate::Version; |
2 | | -#[cfg(feature = "validate")] |
3 | | -use jsonschema::ValidationError; |
4 | 2 | use thiserror::Error; |
5 | 3 |
|
6 | 4 | /// Error enum for crate-specific errors. |
@@ -135,33 +133,84 @@ pub enum Error { |
135 | 133 | Url(#[from] url::ParseError), |
136 | 134 |
|
137 | 135 | /// A list of validation errors. |
138 | | - /// |
139 | | - /// Since we usually don't have the original [serde_json::Value] (because we |
140 | | - /// create them from the STAC objects), we need these errors to be `'static` |
141 | | - /// lifetime. |
142 | | - #[error("validation errors")] |
| 136 | + #[error("{} validation error(s)", .0.len())] |
| 137 | + #[cfg(feature = "validate")] |
| 138 | + Validation(Vec<Validation>), |
| 139 | + |
| 140 | + /// [jsonschema::ValidationError] |
143 | 141 | #[cfg(feature = "validate")] |
144 | | - Validation(Vec<ValidationError<'static>>), |
| 142 | + #[error(transparent)] |
| 143 | + JsonschemaValidation(#[from] jsonschema::ValidationError<'static>), |
| 144 | +} |
| 145 | + |
| 146 | +/// A validation error |
| 147 | +#[cfg(feature = "validate")] |
| 148 | +#[derive(Debug)] |
| 149 | +pub struct Validation { |
| 150 | + /// The ID of the STAC object that failed to validate. |
| 151 | + id: Option<String>, |
| 152 | + |
| 153 | + /// The type of the STAC object that failed to validate. |
| 154 | + r#type: Option<crate::Type>, |
| 155 | + |
| 156 | + /// The validation error. |
| 157 | + error: jsonschema::ValidationError<'static>, |
| 158 | +} |
| 159 | + |
| 160 | +#[cfg(feature = "validate")] |
| 161 | +impl Validation { |
| 162 | + pub(crate) fn new( |
| 163 | + error: jsonschema::ValidationError<'_>, |
| 164 | + value: Option<&serde_json::Value>, |
| 165 | + ) -> Validation { |
| 166 | + use std::borrow::Cow; |
| 167 | + |
| 168 | + // Cribbed from https://docs.rs/jsonschema/latest/src/jsonschema/error.rs.html#21-30 |
| 169 | + let error = jsonschema::ValidationError { |
| 170 | + instance_path: error.instance_path.clone(), |
| 171 | + instance: Cow::Owned(error.instance.into_owned()), |
| 172 | + kind: error.kind, |
| 173 | + schema_path: error.schema_path, |
| 174 | + }; |
| 175 | + let mut id = None; |
| 176 | + let mut r#type = None; |
| 177 | + if let Some(value) = value.and_then(|v| v.as_object()) { |
| 178 | + id = value.get("id").and_then(|v| v.as_str()).map(String::from); |
| 179 | + r#type = value |
| 180 | + .get("type") |
| 181 | + .and_then(|v| v.as_str()) |
| 182 | + .and_then(|s| s.parse::<crate::Type>().ok()); |
| 183 | + } |
| 184 | + Validation { id, r#type, error } |
| 185 | + } |
145 | 186 | } |
146 | 187 |
|
147 | 188 | #[cfg(feature = "validate")] |
148 | 189 | impl Error { |
149 | | - pub(crate) fn from_validation_errors<'a, I>(errors: I) -> Error |
| 190 | + pub(crate) fn from_validation_errors<'a, I>( |
| 191 | + errors: I, |
| 192 | + value: Option<&serde_json::Value>, |
| 193 | + ) -> Error |
150 | 194 | where |
151 | | - I: Iterator<Item = ValidationError<'a>>, |
| 195 | + I: Iterator<Item = jsonschema::ValidationError<'a>>, |
152 | 196 | { |
153 | | - use std::borrow::Cow; |
| 197 | + Error::Validation(errors.map(|error| Validation::new(error, value)).collect()) |
| 198 | + } |
| 199 | +} |
154 | 200 |
|
155 | | - let mut error_vec = Vec::new(); |
156 | | - for error in errors { |
157 | | - // Cribbed from https://docs.rs/jsonschema/latest/src/jsonschema/error.rs.html#21-30 |
158 | | - error_vec.push(ValidationError { |
159 | | - instance_path: error.instance_path.clone(), |
160 | | - instance: Cow::Owned(error.instance.into_owned()), |
161 | | - kind: error.kind, |
162 | | - schema_path: error.schema_path, |
163 | | - }) |
| 201 | +#[cfg(feature = "validate")] |
| 202 | +impl std::fmt::Display for Validation { |
| 203 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 204 | + if let Some(r#type) = self.r#type { |
| 205 | + if let Some(id) = self.id.as_ref() { |
| 206 | + write!(f, "{}[id={id}]: {}", r#type, self.error) |
| 207 | + } else { |
| 208 | + write!(f, "{}: {}", r#type, self.error) |
| 209 | + } |
| 210 | + } else if let Some(id) = self.id.as_ref() { |
| 211 | + write!(f, "[id={id}]: {}", self.error) |
| 212 | + } else { |
| 213 | + write!(f, "{}", self.error) |
164 | 214 | } |
165 | | - Error::Validation(error_vec) |
166 | 215 | } |
167 | 216 | } |
0 commit comments