Skip to main content

rulemorph/
error.rs

1#[derive(Debug, Clone, PartialEq, Eq)]
2pub enum ErrorCode {
3    InvalidVersion,
4    MissingInputFormat,
5    InvalidInputFormat,
6    MissingCsvSection,
7    MissingJsonSection,
8    InvalidDelimiterLength,
9    MissingCsvColumns,
10
11    MissingTarget,
12    DuplicateTarget,
13    SourceValueExprExclusive,
14    MissingMappingValue,
15    InvalidWhenType,
16
17    InvalidRefNamespace,
18    ForwardOutReference,
19    UnknownOp,
20    InvalidArgs,
21    InvalidExprShape,
22    InvalidPath,
23
24    InvalidTypeName,
25
26    // v2 validation errors
27    UndefinedVariable,
28    InvalidItemRef,
29    InvalidAccRef,
30    CyclicDependency,
31    EmptyPipe,
32    InvalidPipeStep,
33
34    // v2 rule structure errors
35    MissingMappings,
36    StepsMappingExclusive,
37    InvalidStep,
38    InvalidFinalize,
39}
40
41impl ErrorCode {
42    pub fn as_str(&self) -> &'static str {
43        match self {
44            ErrorCode::InvalidVersion => "InvalidVersion",
45            ErrorCode::MissingInputFormat => "MissingInputFormat",
46            ErrorCode::InvalidInputFormat => "InvalidInputFormat",
47            ErrorCode::MissingCsvSection => "MissingCsvSection",
48            ErrorCode::MissingJsonSection => "MissingJsonSection",
49            ErrorCode::InvalidDelimiterLength => "InvalidDelimiterLength",
50            ErrorCode::MissingCsvColumns => "MissingCsvColumns",
51            ErrorCode::MissingTarget => "MissingTarget",
52            ErrorCode::DuplicateTarget => "DuplicateTarget",
53            ErrorCode::SourceValueExprExclusive => "SourceValueExprExclusive",
54            ErrorCode::MissingMappingValue => "MissingMappingValue",
55            ErrorCode::InvalidWhenType => "InvalidWhenType",
56            ErrorCode::InvalidRefNamespace => "InvalidRefNamespace",
57            ErrorCode::ForwardOutReference => "ForwardOutReference",
58            ErrorCode::UnknownOp => "UnknownOp",
59            ErrorCode::InvalidArgs => "InvalidArgs",
60            ErrorCode::InvalidExprShape => "InvalidExprShape",
61            ErrorCode::InvalidPath => "InvalidPath",
62            ErrorCode::InvalidTypeName => "InvalidTypeName",
63            ErrorCode::UndefinedVariable => "UndefinedVariable",
64            ErrorCode::InvalidItemRef => "InvalidItemRef",
65            ErrorCode::InvalidAccRef => "InvalidAccRef",
66            ErrorCode::CyclicDependency => "CyclicDependency",
67            ErrorCode::EmptyPipe => "EmptyPipe",
68            ErrorCode::InvalidPipeStep => "InvalidPipeStep",
69            ErrorCode::MissingMappings => "MissingMappings",
70            ErrorCode::StepsMappingExclusive => "StepsMappingExclusive",
71            ErrorCode::InvalidStep => "InvalidStep",
72            ErrorCode::InvalidFinalize => "InvalidFinalize",
73        }
74    }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct YamlLocation {
79    pub line: usize,
80    pub column: usize,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct RuleError {
85    pub code: ErrorCode,
86    pub message: String,
87    pub location: Option<YamlLocation>,
88    pub path: Option<String>,
89}
90
91impl RuleError {
92    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
93        Self {
94            code,
95            message: message.into(),
96            location: None,
97            path: None,
98        }
99    }
100
101    pub fn with_path(mut self, path: impl Into<String>) -> Self {
102        self.path = Some(path.into());
103        self
104    }
105
106    pub fn with_location(mut self, line: usize, column: usize) -> Self {
107        self.location = Some(YamlLocation { line, column });
108        self
109    }
110}
111
112pub type ValidationResult = Result<(), Vec<RuleError>>;
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub enum TransformErrorKind {
116    InvalidInput,
117    InvalidRecordsPath,
118    InvalidRef,
119    InvalidTarget,
120    MissingRequired,
121    TypeCastFailed,
122    ExprError,
123    AssertionFailed,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct TransformWarning {
128    pub kind: TransformErrorKind,
129    pub message: String,
130    pub path: Option<String>,
131}
132
133impl TransformWarning {
134    pub fn new(kind: TransformErrorKind, message: impl Into<String>) -> Self {
135        Self {
136            kind,
137            message: message.into(),
138            path: None,
139        }
140    }
141
142    pub fn with_path(mut self, path: impl Into<String>) -> Self {
143        self.path = Some(path.into());
144        self
145    }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct TransformError {
150    pub kind: TransformErrorKind,
151    pub message: String,
152    pub path: Option<String>,
153}
154
155impl TransformError {
156    pub fn new(kind: TransformErrorKind, message: impl Into<String>) -> Self {
157        Self {
158            kind,
159            message: message.into(),
160            path: None,
161        }
162    }
163
164    pub fn with_path(mut self, path: impl Into<String>) -> Self {
165        self.path = Some(path.into());
166        self
167    }
168}
169
170impl std::fmt::Display for TransformError {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        if let Some(path) = &self.path {
173            write!(f, "{} (path: {})", self.message, path)
174        } else {
175            write!(f, "{}", self.message)
176        }
177    }
178}
179
180impl std::error::Error for TransformError {}
181
182impl From<TransformError> for TransformWarning {
183    fn from(err: TransformError) -> Self {
184        let mut warning = TransformWarning::new(err.kind, err.message);
185        if let Some(path) = err.path {
186            warning = warning.with_path(path);
187        }
188        warning
189    }
190}
191
192impl From<csv::Error> for TransformError {
193    fn from(err: csv::Error) -> Self {
194        TransformError::new(
195            TransformErrorKind::InvalidInput,
196            format!("csv error: {}", err),
197        )
198    }
199}
200
201impl From<serde_json::Error> for TransformError {
202    fn from(err: serde_json::Error) -> Self {
203        TransformError::new(
204            TransformErrorKind::InvalidInput,
205            format!("json error: {}", err),
206        )
207    }
208}