1use std::{
2 fmt::{Debug, Display},
3 sync::Arc,
4};
5
6pub struct CrawlerError {
7 inner: Box<ErrorKind>,
8}
9
10pub type CrawlerResult<T> = std::result::Result<T, CrawlerError>;
11
12enum ErrorKind {
14 ArraySize {
16 key: String,
18 json: Arc<String>,
22 min_elements: usize,
24 },
25 PathNotFoundInArray {
27 key: String,
29 json: Arc<String>,
33 target_path: String,
36 },
37 PathsNotFound {
39 key: String,
41 json: Arc<String>,
45 target_paths: Vec<String>,
47 },
48 Parsing {
52 key: String,
54 json: Arc<String>,
58 target: ParseTarget,
60 message: Option<String>,
63 },
64 Navigation {
66 key: String,
68 json: Arc<String>,
72 },
73 MultipleParseError {
75 key: String,
76 json: Arc<String>,
77 messages: Vec<String>,
78 },
79}
80
81#[derive(Debug, Clone)]
83pub(crate) enum ParseTarget {
84 Array,
85 Other(String),
86}
87
88impl std::fmt::Display for ParseTarget {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 match self {
91 ParseTarget::Array => write!(f, "Array"),
92 ParseTarget::Other(t) => write!(f, "{t}"),
93 }
94 }
95}
96
97impl std::error::Error for CrawlerError {}
98
99impl CrawlerError {
100 pub fn get_json_and_key(&self) -> (String, &String) {
102 match self.inner.as_ref() {
103 ErrorKind::Navigation { json, key } => (json.to_string(), key),
104 ErrorKind::Parsing { json, key, .. } => (json.to_string(), key),
105 ErrorKind::PathNotFoundInArray { key, json, .. } => (json.to_string(), key),
106 ErrorKind::PathsNotFound { key, json, .. } => (json.to_string(), key),
107 ErrorKind::ArraySize { key, json, .. } => (json.to_string(), key),
108 ErrorKind::MultipleParseError { key, json, .. } => (json.to_string(), key),
109 }
110 }
111 pub(crate) fn multiple_parse_error(
112 key: impl Into<String>,
113 json: Arc<String>,
114 errors: Vec<CrawlerError>,
115 ) -> Self {
116 let messages = errors.into_iter().map(|e| format!("{e}")).collect();
117 Self {
118 inner: Box::new(ErrorKind::MultipleParseError {
119 key: key.into(),
120 json,
121 messages,
122 }),
123 }
124 }
125 pub(crate) fn navigation(key: impl Into<String>, json: Arc<String>) -> Self {
126 Self {
127 inner: Box::new(ErrorKind::Navigation {
128 key: key.into(),
129 json,
130 }),
131 }
132 }
133 pub(crate) fn array_size(
134 key: impl Into<String>,
135 json: Arc<String>,
136 min_elements: usize,
137 ) -> Self {
138 let key = key.into();
139 Self {
140 inner: Box::new(ErrorKind::ArraySize {
141 key,
142 json,
143 min_elements,
144 }),
145 }
146 }
147 pub(crate) fn path_not_found_in_array(
148 key: impl Into<String>,
149 json: Arc<String>,
150 target_path: impl Into<String>,
151 ) -> Self {
152 let key = key.into();
153 let target_path = target_path.into();
154 Self {
155 inner: Box::new(ErrorKind::PathNotFoundInArray {
156 key,
157 json,
158 target_path,
159 }),
160 }
161 }
162 pub(crate) fn paths_not_found(
163 key: impl Into<String>,
164 json: Arc<String>,
165 target_paths: Vec<String>,
166 ) -> Self {
167 let key = key.into();
168 Self {
169 inner: Box::new(ErrorKind::PathsNotFound {
170 key,
171 json,
172 target_paths,
173 }),
174 }
175 }
176 pub(crate) fn parsing<S: Into<String>>(
177 key: S,
178 json: Arc<String>,
179 target: ParseTarget,
180 message: Option<String>,
181 ) -> Self {
182 Self {
183 inner: Box::new(ErrorKind::Parsing {
184 key: key.into(),
185 json,
186 target,
187 message,
188 }),
189 }
190 }
191}
192impl Display for ErrorKind {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 match self {
195 ErrorKind::PathsNotFound {
196 key, target_paths, ..
197 } => write!(
198 f,
199 "Expected {key} to contain one of the following paths: {:?}",
200 target_paths
201 ),
202 ErrorKind::PathNotFoundInArray {
203 key, target_path, ..
204 } => write!(f, "Expected {key} to contain a {target_path}"),
205 ErrorKind::Navigation { key, json: _ } => {
206 write!(f, "Key {key} not found in Api response.")
207 }
208 ErrorKind::ArraySize {
209 key,
210 json: _,
211 min_elements,
212 } => {
213 write!(
214 f,
215 "Expected {key} to contain at least {min_elements} elements."
216 )
217 }
218 ErrorKind::Parsing {
219 key,
220 json: _,
221 target,
222 message,
223 } => write!(
224 f,
225 "Error {}. Unable to parse into {target} at {key}",
226 message.as_deref().unwrap_or_default()
227 ),
228 ErrorKind::MultipleParseError { key, json: _, messages } => write!(f,"Expected one of the parsing functions at {key} to succeed, but all failed with the following errors: {:?}",messages),
229 }
230 }
231}
232
233impl Debug for CrawlerError {
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 Display::fmt(&*self.inner, f)
239 }
240}
241impl Display for CrawlerError {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 Display::fmt(&*self.inner, f)
244 }
245}