1use thiserror::Error;
4
5#[derive(Debug, Clone, PartialEq, Eq, Error)]
7pub enum EffectRuntimeValidationError {
8 #[error("missing required field: {0}")]
9 MissingField(&'static str),
10 #[error("invalid schema version for {artifact}: expected {expected}, found {found}")]
11 InvalidSchemaVersion {
12 artifact: &'static str,
13 expected: &'static str,
14 found: String,
15 },
16 #[error("invalid artifact state: {0}")]
17 InvalidState(&'static str),
18 #[error("invalid timestamp in field {field}: {value}")]
19 InvalidTimestamp { field: &'static str, value: String },
20}
21
22impl EffectRuntimeValidationError {
23 pub fn kind(&self) -> &'static str {
25 match self {
26 Self::MissingField(..) => "missing_field",
27 Self::InvalidSchemaVersion { .. } => "invalid_schema_version",
28 Self::InvalidState(..) => "invalid_state",
29 Self::InvalidTimestamp { .. } => "invalid_timestamp",
30 }
31 }
32}
33
34pub type EffectValidationResult = Result<(), EffectRuntimeValidationError>;
36
37pub(crate) fn require_non_empty(value: &str, field: &'static str) -> EffectValidationResult {
38 if value.trim().is_empty() {
39 return Err(EffectRuntimeValidationError::MissingField(field));
40 }
41 Ok(())
42}
43
44pub(crate) fn require_id(value: &impl AsRef<str>, field: &'static str) -> EffectValidationResult {
45 require_non_empty(value.as_ref(), field)
46}
47
48pub(crate) fn require_non_empty_slice<T>(
49 values: &[T],
50 field: &'static str,
51) -> EffectValidationResult {
52 if values.is_empty() {
53 return Err(EffectRuntimeValidationError::MissingField(field));
54 }
55 Ok(())
56}
57
58pub(crate) fn require_valid_timestamp(value: &str, field: &'static str) -> EffectValidationResult {
59 if value.trim().is_empty() {
60 return Err(EffectRuntimeValidationError::MissingField(field));
61 }
62 chrono::DateTime::parse_from_rfc3339(value).map_err(|_| {
63 EffectRuntimeValidationError::InvalidTimestamp {
64 field,
65 value: value.to_string(),
66 }
67 })?;
68 Ok(())
69}
70
71pub(crate) fn require_schema_version(
72 artifact: &'static str,
73 expected: &'static str,
74 found: &str,
75) -> EffectValidationResult {
76 if found != expected {
77 return Err(EffectRuntimeValidationError::InvalidSchemaVersion {
78 artifact,
79 expected,
80 found: found.to_string(),
81 });
82 }
83 Ok(())
84}