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}