1use yog_data::{Diagnostic, Path, Schema};
6
7#[derive(Debug, Clone, Default, PartialEq, Schema)]
9pub(crate) struct ServiceError {
10 pub(crate) message: String,
11 #[data(default)]
13 pub(crate) problems: Vec<Diagnostic>,
14 pub(crate) file: Option<String>,
16}
17
18impl ServiceError {
19 pub(crate) fn of(code: &str, message: impl Into<String>) -> Self {
21 let message = message.into();
22 ServiceError {
23 problems: vec![Diagnostic::error(code, &message)],
24 message,
25 file: None,
26 }
27 }
28
29 pub(crate) fn at(code: &str, message: impl Into<String>, line: u32, col: Option<u32>) -> Self {
31 let mut e = Self::of(code, message);
32 e.problems[0].line = Some(line);
33 e.problems[0].col = col;
34 e
35 }
36
37 pub(crate) fn syntax(e: &yog_data::SyntaxError) -> Self {
39 Self::at(
40 yog_ids::data_problem::SYNTAX,
41 e.message.clone(),
42 e.at.line,
43 Some(e.at.col),
44 )
45 }
46
47 pub(crate) fn not_found(message: impl Into<String>) -> Self {
49 Self::of(yog_ids::request_problem::NOT_FOUND, message)
50 }
51
52 pub(crate) fn param(name: &str, problems: Vec<Diagnostic>) -> Self {
54 let param = Path::root().key(name);
55 let problems: Vec<Diagnostic> = problems
56 .into_iter()
57 .map(|p| {
58 let path = param.then(&p.path);
59 p.at_path(path)
60 })
61 .collect();
62 let message = match problems.as_slice() {
63 [one] => format!("`{}`: {}", one.path, one.message),
64 _ => format!("`{name}` has {} problems", problems.len()),
65 };
66 ServiceError {
67 message,
68 problems,
69 file: None,
70 }
71 }
72}
73
74impl From<String> for ServiceError {
75 fn from(message: String) -> Self {
76 Self::of(yog_ids::request_problem::FAILED, message)
77 }
78}
79
80impl From<&str> for ServiceError {
81 fn from(message: &str) -> Self {
82 message.to_string().into()
83 }
84}
85
86impl From<yog_data::Errors> for ServiceError {
88 fn from(found: yog_data::Errors) -> Self {
89 ServiceError {
90 message: found.to_string(),
91 problems: found.0,
92 file: None,
93 }
94 }
95}