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