1use crate::ast::Span;
9use thiserror::Error;
10
11#[derive(Debug, Clone, PartialEq, Eq, Error)]
13pub enum PlannerError {
14 #[error("invalid PRAGMA '{name}': {reason}")]
16 InvalidPragma { name: String, reason: String },
17 #[error("error[ALOPEX-C001]: table '{name}' not found at line {line}, column {column}")]
20 TableNotFound {
21 name: String,
22 line: u64,
23 column: u64,
24 },
25
26 #[error("error[ALOPEX-C002]: table '{name}' already exists")]
28 TableAlreadyExists { name: String },
29
30 #[error(
32 "error[ALOPEX-C003]: column '{column}' not found in table '{table}' at line {line}, column {col}"
33 )]
34 ColumnNotFound {
35 column: String,
36 table: String,
37 line: u64,
38 col: u64,
39 },
40
41 #[error(
43 "error[ALOPEX-C004]: ambiguous column '{column}' found in tables: {tables:?} at line {line}, column {col}"
44 )]
45 AmbiguousColumn {
46 column: String,
47 tables: Vec<String>,
48 line: u64,
49 col: u64,
50 },
51
52 #[error("error[ALOPEX-C005]: index '{name}' already exists")]
54 IndexAlreadyExists { name: String },
55
56 #[error("error[ALOPEX-C006]: index '{name}' not found")]
58 IndexNotFound { name: String },
59
60 #[error(
63 "error[ALOPEX-T001]: type mismatch at line {line}, column {column}: expected {expected}, found {found}"
64 )]
65 TypeMismatch {
66 expected: String,
67 found: String,
68 line: u64,
69 column: u64,
70 },
71
72 #[error(
74 "error[ALOPEX-T002]: invalid operator '{op}' for type '{type_name}' at line {line}, column {column}"
75 )]
76 InvalidOperator {
77 op: String,
78 type_name: String,
79 line: u64,
80 column: u64,
81 },
82
83 #[error(
85 "error[ALOPEX-T003]: null constraint violation for column '{column}' at line {line}, column {col}"
86 )]
87 NullConstraintViolation { column: String, line: u64, col: u64 },
88
89 #[error(
91 "error[ALOPEX-T004]: vector dimension mismatch at line {line}, column {column}: expected {expected}, found {found}"
92 )]
93 VectorDimensionMismatch {
94 expected: u32,
95 found: u32,
96 line: u64,
97 column: u64,
98 },
99
100 #[error(
102 "error[ALOPEX-T005]: invalid metric '{value}' at line {line}, column {column}. Valid options: cosine, l2, inner"
103 )]
104 InvalidMetric {
105 value: String,
106 line: u64,
107 column: u64,
108 },
109
110 #[error(
112 "error[ALOPEX-T006]: column count ({columns}) does not match value count ({values}) at line {line}, column {column}"
113 )]
114 ColumnValueCountMismatch {
115 columns: usize,
116 values: usize,
117 line: u64,
118 column: u64,
119 },
120
121 #[error("error[ALOPEX-T007]: invalid expression: {message}")]
123 InvalidExpression { message: String },
124
125 #[error(
127 "error[ALOPEX-T008]: set operation column count mismatch: left {left}, right {right} at line {line}, column {column}"
128 )]
129 SetOperationColumnCountMismatch {
130 left: usize,
131 right: usize,
132 line: u64,
133 column: u64,
134 },
135
136 #[error(
138 "error[ALOPEX-T009]: common table expression '{cte}' declares {declared} column names but its query returns {actual} columns at line {line}, column {column}"
139 )]
140 CteColumnCountMismatch {
141 cte: String,
142 declared: usize,
143 actual: usize,
144 line: u64,
145 column: u64,
146 },
147
148 #[error(
150 "error[ALOPEX-T010]: common table expression '{cte}' declares column '{name}' more than once at line {line}, column {column}"
151 )]
152 DuplicateCteColumn {
153 cte: String,
154 name: String,
155 line: u64,
156 column: u64,
157 },
158
159 #[error(
162 "error[ALOPEX-F001]: feature '{feature}' is not supported in this version. Expected in {version}"
163 )]
164 UnsupportedFeature {
165 feature: String,
166 version: String,
167 line: u64,
168 column: u64,
169 },
170}
171
172impl PlannerError {
173 pub fn table_not_found(name: impl Into<String>, span: Span) -> Self {
175 Self::TableNotFound {
176 name: name.into(),
177 line: span.start.line,
178 column: span.start.column,
179 }
180 }
181
182 pub fn table_already_exists(name: impl Into<String>) -> Self {
184 Self::TableAlreadyExists { name: name.into() }
185 }
186
187 pub fn column_not_found(
189 column: impl Into<String>,
190 table: impl Into<String>,
191 span: Span,
192 ) -> Self {
193 Self::ColumnNotFound {
194 column: column.into(),
195 table: table.into(),
196 line: span.start.line,
197 col: span.start.column,
198 }
199 }
200
201 pub fn ambiguous_column(column: impl Into<String>, tables: Vec<String>, span: Span) -> Self {
203 Self::AmbiguousColumn {
204 column: column.into(),
205 tables,
206 line: span.start.line,
207 col: span.start.column,
208 }
209 }
210
211 pub fn index_already_exists(name: impl Into<String>) -> Self {
213 Self::IndexAlreadyExists { name: name.into() }
214 }
215
216 pub fn index_not_found(name: impl Into<String>) -> Self {
218 Self::IndexNotFound { name: name.into() }
219 }
220
221 pub fn type_mismatch(
223 expected: impl Into<String>,
224 found: impl Into<String>,
225 span: Span,
226 ) -> Self {
227 Self::TypeMismatch {
228 expected: expected.into(),
229 found: found.into(),
230 line: span.start.line,
231 column: span.start.column,
232 }
233 }
234
235 pub fn invalid_expression(message: impl Into<String>) -> Self {
237 Self::InvalidExpression {
238 message: message.into(),
239 }
240 }
241
242 pub fn set_operation_column_count_mismatch(left: usize, right: usize, span: Span) -> Self {
244 Self::SetOperationColumnCountMismatch {
245 left,
246 right,
247 line: span.start.line,
248 column: span.start.column,
249 }
250 }
251
252 pub fn cte_column_count_mismatch(
254 cte: impl Into<String>,
255 declared: usize,
256 actual: usize,
257 span: Span,
258 ) -> Self {
259 Self::CteColumnCountMismatch {
260 cte: cte.into(),
261 declared,
262 actual,
263 line: span.start.line,
264 column: span.start.column,
265 }
266 }
267
268 pub fn duplicate_cte_column(
270 cte: impl Into<String>,
271 column_name: impl Into<String>,
272 span: Span,
273 ) -> Self {
274 Self::DuplicateCteColumn {
275 cte: cte.into(),
276 name: column_name.into(),
277 line: span.start.line,
278 column: span.start.column,
279 }
280 }
281
282 pub fn invalid_operator(
284 op: impl Into<String>,
285 type_name: impl Into<String>,
286 span: Span,
287 ) -> Self {
288 Self::InvalidOperator {
289 op: op.into(),
290 type_name: type_name.into(),
291 line: span.start.line,
292 column: span.start.column,
293 }
294 }
295
296 pub fn null_constraint_violation(column: impl Into<String>, span: Span) -> Self {
298 Self::NullConstraintViolation {
299 column: column.into(),
300 line: span.start.line,
301 col: span.start.column,
302 }
303 }
304
305 pub fn vector_dimension_mismatch(expected: u32, found: u32, span: Span) -> Self {
307 Self::VectorDimensionMismatch {
308 expected,
309 found,
310 line: span.start.line,
311 column: span.start.column,
312 }
313 }
314
315 pub fn invalid_metric(value: impl Into<String>, span: Span) -> Self {
317 Self::InvalidMetric {
318 value: value.into(),
319 line: span.start.line,
320 column: span.start.column,
321 }
322 }
323
324 pub fn column_value_count_mismatch(columns: usize, values: usize, span: Span) -> Self {
326 Self::ColumnValueCountMismatch {
327 columns,
328 values,
329 line: span.start.line,
330 column: span.start.column,
331 }
332 }
333
334 pub fn unsupported_feature(
336 feature: impl Into<String>,
337 version: impl Into<String>,
338 span: Span,
339 ) -> Self {
340 Self::UnsupportedFeature {
341 feature: feature.into(),
342 version: version.into(),
343 line: span.start.line,
344 column: span.start.column,
345 }
346 }
347}