sqry_core/query/builder/
error.rs1use crate::query::Operator;
4use std::fmt;
5
6#[derive(Debug, Clone)]
8pub enum BuildError {
9 UnknownField {
11 field: String,
13 available: String,
15 },
16
17 InvalidOperator {
19 field: String,
21 operator: Operator,
23 field_type: String,
25 },
26
27 ValueTypeMismatch {
29 field: String,
31 expected: String,
33 actual: String,
35 },
36
37 InvalidEnumValue {
39 field: String,
41 value: String,
43 valid: String,
45 },
46
47 InvalidRegex(regex::Error),
49
50 InvalidFancyRegex {
52 pattern: String,
54 error: String,
56 },
57
58 EmptyQuery,
60
61 Multiple(Vec<BuildError>),
63}
64
65impl fmt::Display for BuildError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 BuildError::UnknownField { field, available } => {
69 write!(f, "unknown field '{field}', available fields: {available}")
70 }
71 BuildError::InvalidOperator {
72 field,
73 operator,
74 field_type,
75 } => {
76 write!(
77 f,
78 "operator '{operator:?}' not valid for field '{field}' (type: {field_type})"
79 )
80 }
81 BuildError::ValueTypeMismatch {
82 field,
83 expected,
84 actual,
85 } => {
86 write!(
87 f,
88 "value type mismatch for field '{field}': expected {expected}, got {actual}"
89 )
90 }
91 BuildError::InvalidEnumValue {
92 field,
93 value,
94 valid,
95 } => {
96 write!(
97 f,
98 "invalid enum value '{value}' for field '{field}', valid values: {valid}"
99 )
100 }
101 BuildError::InvalidRegex(e) => {
102 write!(f, "invalid regex pattern: {e}")
103 }
104 BuildError::InvalidFancyRegex { pattern, error } => {
105 write!(f, "invalid regex pattern '{pattern}': {error}")
106 }
107 BuildError::EmptyQuery => {
108 write!(f, "empty query: no conditions specified")
109 }
110 BuildError::Multiple(errors) => {
111 write!(f, "multiple validation errors:")?;
112 for (i, err) in errors.iter().enumerate() {
113 write!(f, "\n {}: {err}", i + 1)?;
114 }
115 Ok(())
116 }
117 }
118 }
119}
120
121impl std::error::Error for BuildError {
122 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123 match self {
124 BuildError::InvalidRegex(e) => Some(e),
125 _ => None,
126 }
127 }
128}
129
130impl From<regex::Error> for BuildError {
131 fn from(err: regex::Error) -> Self {
132 BuildError::InvalidRegex(err)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_unknown_field_display() {
142 let err = BuildError::UnknownField {
143 field: "foo".to_string(),
144 available: "kind, name, path".to_string(),
145 };
146 assert_eq!(
147 err.to_string(),
148 "unknown field 'foo', available fields: kind, name, path"
149 );
150 }
151
152 #[test]
153 fn test_invalid_operator_display() {
154 let err = BuildError::InvalidOperator {
155 field: "kind".to_string(),
156 operator: Operator::Greater,
157 field_type: "Enum".to_string(),
158 };
159 assert!(err.to_string().contains("operator"));
160 assert!(err.to_string().contains("kind"));
161 }
162
163 #[test]
164 fn test_value_type_mismatch_display() {
165 let err = BuildError::ValueTypeMismatch {
166 field: "name".to_string(),
167 expected: "String".to_string(),
168 actual: "Number".to_string(),
169 };
170 assert!(err.to_string().contains("value type mismatch"));
171 assert!(err.to_string().contains("expected String"));
172 }
173
174 #[test]
175 fn test_invalid_enum_value_display() {
176 let err = BuildError::InvalidEnumValue {
177 field: "kind".to_string(),
178 value: "invalid".to_string(),
179 valid: "function, class, method".to_string(),
180 };
181 assert!(err.to_string().contains("invalid enum value"));
182 assert!(err.to_string().contains("function, class, method"));
183 }
184
185 #[test]
186 fn test_empty_query_display() {
187 let err = BuildError::EmptyQuery;
188 assert_eq!(err.to_string(), "empty query: no conditions specified");
189 }
190
191 #[test]
192 fn test_multiple_errors_display() {
193 let err = BuildError::Multiple(vec![
194 BuildError::EmptyQuery,
195 BuildError::UnknownField {
196 field: "foo".to_string(),
197 available: "kind".to_string(),
198 },
199 ]);
200 let msg = err.to_string();
201 assert!(msg.contains("multiple validation errors"));
202 assert!(msg.contains("empty query"));
203 assert!(msg.contains("unknown field"));
204 }
205
206 #[test]
207 #[allow(clippy::invalid_regex)] fn test_regex_error_conversion() {
209 let regex_err = regex::Regex::new("[invalid").unwrap_err();
210 let build_err: BuildError = regex_err.into();
211 assert!(matches!(build_err, BuildError::InvalidRegex(_)));
212 assert!(build_err.to_string().contains("invalid regex pattern"));
213 }
214}