reifydb_routine/procedure/
error.rs1use reifydb_type::{
5 error::{Diagnostic, Error, IntoDiagnostic, TypeError},
6 fragment::Fragment,
7 value::r#type::Type,
8};
9
10#[derive(Debug, thiserror::Error)]
11pub enum ProcedureError {
12 #[error("procedure {} expects {expected} arguments, got {actual}", procedure.text())]
13 ArityMismatch {
14 procedure: Fragment,
15 expected: usize,
16 actual: usize,
17 },
18
19 #[error("procedure {} argument {} has invalid type: got {actual:?}", procedure.text(), argument_index + 1)]
20 InvalidArgumentType {
21 procedure: Fragment,
22 argument_index: usize,
23 expected: Vec<Type>,
24 actual: Type,
25 },
26
27 #[error("procedure {} execution failed: {reason}", procedure.text())]
28 ExecutionFailed {
29 procedure: Fragment,
30 reason: String,
31 },
32
33 #[error(transparent)]
34 Wrapped(Box<Error>),
35}
36
37impl From<Error> for ProcedureError {
38 fn from(err: Error) -> Self {
39 ProcedureError::Wrapped(Box::new(err))
40 }
41}
42
43impl From<TypeError> for ProcedureError {
44 fn from(err: TypeError) -> Self {
45 ProcedureError::Wrapped(Box::new(Error::from(err)))
46 }
47}
48
49impl ProcedureError {
50 pub fn with_context(self, procedure: Fragment) -> Error {
54 match self {
55 ProcedureError::Wrapped(inner) => {
56 let name = procedure.text().to_string();
57 let mut cause = inner.0;
58 cause.with_fragment(procedure.clone());
59 Error(Diagnostic {
60 code: "PROCEDURE_003".to_string(),
61 statement: None,
62 message: format!("Procedure {} execution failed", name),
63 column: None,
64 fragment: procedure,
65 label: Some("execution failed".to_string()),
66 help: Some("Check procedure arguments and context".to_string()),
67 notes: vec![],
68 cause: Some(Box::new(cause)),
69 operator_chain: None,
70 })
71 }
72 other => Error(other.into_diagnostic()),
73 }
74 }
75}
76
77impl From<ProcedureError> for Error {
78 fn from(err: ProcedureError) -> Self {
79 Error(err.into_diagnostic())
80 }
81}
82
83impl IntoDiagnostic for ProcedureError {
84 fn into_diagnostic(self) -> Diagnostic {
85 match self {
86 ProcedureError::ArityMismatch {
87 procedure,
88 expected,
89 actual,
90 } => {
91 let name = procedure.text().to_string();
92 Diagnostic {
93 code: "PROCEDURE_001".to_string(),
94 statement: None,
95 message: format!(
96 "Procedure {} expects {} arguments, got {}",
97 name, expected, actual
98 ),
99 column: None,
100 fragment: procedure,
101 label: Some("wrong number of arguments".to_string()),
102 help: Some(format!(
103 "Provide exactly {} arguments to procedure {}",
104 expected, name
105 )),
106 notes: vec![],
107 cause: None,
108 operator_chain: None,
109 }
110 }
111 ProcedureError::InvalidArgumentType {
112 procedure,
113 argument_index,
114 expected,
115 actual,
116 } => {
117 let name = procedure.text().to_string();
118 let expected_types =
119 expected.iter().map(|t| format!("{:?}", t)).collect::<Vec<_>>().join(", ");
120 Diagnostic {
121 code: "PROCEDURE_002".to_string(),
122 statement: None,
123 message: format!(
124 "Procedure {} argument {} has invalid type: expected one of [{}], got {:?}",
125 name,
126 argument_index + 1,
127 expected_types,
128 actual
129 ),
130 column: None,
131 fragment: procedure,
132 label: Some("invalid argument type".to_string()),
133 help: Some(format!("Provide an argument of type: {}", expected_types)),
134 notes: vec![],
135 cause: None,
136 operator_chain: None,
137 }
138 }
139 ProcedureError::ExecutionFailed {
140 procedure,
141 reason,
142 } => {
143 let name = procedure.text().to_string();
144 Diagnostic {
145 code: "PROCEDURE_003".to_string(),
146 statement: None,
147 message: format!("Procedure {} execution failed: {}", name, reason),
148 column: None,
149 fragment: procedure,
150 label: Some("execution failed".to_string()),
151 help: Some("Check procedure arguments and context".to_string()),
152 notes: vec![],
153 cause: None,
154 operator_chain: None,
155 }
156 }
157 ProcedureError::Wrapped(err) => err.0,
158 }
159 }
160}