Skip to main content

dpp_domain/domain/
field_error.rs

1//! Field-level validation error types.
2//!
3//! Kept free of any schema/`jsonschema` dependency (unlike the rest of
4//! [`crate::domain::validation`], which is wasm-gated) so that
5//! [`crate::domain::error::DppError`] can carry structured validation detail on
6//! every target, including `wasm32`.
7
8/// A single field-level validation failure.
9#[derive(Debug, Clone, PartialEq)]
10pub struct FieldError {
11    /// JSON pointer path to the failing field, e.g. `"/gtin"` or
12    /// `"/fibreComposition/0/pct"`. Empty when the failure is not tied to a
13    /// specific field.
14    pub field: String,
15    /// Human-readable error message.
16    pub message: String,
17}
18
19/// Collection of field-level errors returned when validation fails.
20///
21/// Always contains at least one entry.
22#[derive(Debug, Clone)]
23pub struct ValidationErrors {
24    pub errors: Vec<FieldError>,
25}
26
27impl ValidationErrors {
28    /// A validation failure carrying a single, field-less message.
29    pub fn message(msg: impl Into<String>) -> Self {
30        Self {
31            errors: vec![FieldError {
32                field: String::new(),
33                message: msg.into(),
34            }],
35        }
36    }
37
38    /// Returns a combined error message listing all failures.
39    pub fn to_display(&self) -> String {
40        self.errors
41            .iter()
42            .map(|e| {
43                if e.field.is_empty() {
44                    e.message.clone()
45                } else {
46                    format!("{}: {}", e.field, e.message)
47                }
48            })
49            .collect::<Vec<_>>()
50            .join("; ")
51    }
52}
53
54impl std::fmt::Display for ValidationErrors {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        write!(f, "{}", self.to_display())
57    }
58}
59
60impl std::error::Error for ValidationErrors {}
61
62impl From<String> for ValidationErrors {
63    fn from(msg: String) -> Self {
64        Self::message(msg)
65    }
66}
67
68impl From<&str> for ValidationErrors {
69    fn from(msg: &str) -> Self {
70        Self::message(msg)
71    }
72}